2017-01-13 3 views
0

У меня есть веб-приложение, которое использует среду Spring вместе с Spring MVC для создания конечных точек REST. Аутентификация обеспечивается контейнером с использованием безопасности Java EE (в частности, области безопасности в Wildfly 9, поддерживаемой Active Directory), а роли загружаются из базы данных приложений. У меня есть обертка запроса, примененная фильтром, чтобы сделать данные пользователя доступными через обычный API сервлета.Использование JSR-250 (@RolesAllowed) аннотации Spring MVC и проверка контейнера

web.xml:

<web-app ... version="3.1"> 

    <security-constraint> 
     <web-resource-collection> 
      <web-resource-name>Unauthenticated Resources</web-resource-name> 
      <url-pattern>/favicon.ico</url-pattern> 
      <url-pattern>/NoAccess.html</url-pattern> 
      <url-pattern>/login</url-pattern> 
      <url-pattern>/css/*</url-pattern> 
      <url-pattern>/font/*</url-pattern> 
      <url-pattern>/images/*</url-pattern> 
      <url-pattern>/js/*</url-pattern> 
      <url-pattern>/lib/*</url-pattern> 
      <url-pattern>/partials/*</url-pattern> 
     </web-resource-collection> 
    </security-constraint> 

    <security-constraint> 
     <web-resource-collection> 
      <web-resource-name>All Resources</web-resource-name> 
      <url-pattern>/*</url-pattern> 
     </web-resource-collection> 
     <auth-constraint> 
      <role-name>*</role-name> 
     </auth-constraint> 
    </security-constraint> 

    <login-config> 
     <auth-method>FORM</auth-method> 
     <realm-name>App Realm</realm-name> 
     <form-login-config> 
      <form-login-page>/Login.jsp</form-login-page> 
      <form-error-page>/NoAccess.html</form-error-page> 
     </form-login-config> 
    </login-config> 

    <security-role> 
     <role-name>*</role-name> 
    </security-role> 

</web-app> 

SecurityFilter.java

@WebFilter(urlPatterns = { "*" }) 
public class SecurityFilter implements Filter { 

    ... 

    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
     HttpServletRequest httpRequest = (HttpServletRequest) request; 
     HttpServletResponse httpResponse = (HttpServletResponse) response; 

     // Don't wrap unauthenticated requests 
     if (httpRequest.getRemoteUser() == null) { 
      chain.doFilter(httpRequest, httpResponse); 
      return; 
     } 

     Person user = this.personRepository.findByLogin(httpRequest.getRemoteUser()); 
     if (user != null) { 
      List<String> roles = this.personRepository.getRoles(user.getId()); 
      HttpServletRequest wrappedRequest = new RequestWrapper(httpRequest, user, roles); 
      chain.doFilter(wrappedRequest, httpResponse); 
     } else { 
      httpResponse.sendRedirect(httpRequest.getContextPath() + "/NoAccess.html"); 
     } 
    } 
} 

Authentication работает и внутри контроллера, я могу сделать request.getUserPrincipal() и request.isUserInRole("SYSTEM_ADMIN") и они правильно вернуться. Теперь я хочу добавить авторизацию в приложение. Я хочу применить правила авторизации, используя аннотацию JSR-250 @RolesPermitted по моим методам контроллера; Я не хочу перечислять все правила в отдельном файле/классе конфигурации. Пример из контроллера:

@RestController 
@RequestMapping("/people") 
public class PersonController { 

    ... 

    @RolesAllowed({Role.SYSTEM_ADMIN, Role.DEPARTMENT_ADMIN, Role.SYSTEM_AUDITOR, Role.AUDITOR}) 
    @RequestMapping 
    public List<Person> listPeople(HttpServletRequest request) { 
     return this.personRepository.getPeople(); 
    } 
} 

Конечно, это ничего не делает сам по себе, поэтому я добавил класс конфигурации с @EnableWebSecurity и @EnableGlobalMethodSecurity(jsr250Enabled = true). Теперь, когда я ударил этот ресурс, я получил ошибку org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: An Authentication object was not found in the SecurityContext. Достаточно справедливо, поэтому я следую примеру https://gist.github.com/virgium03/86938e43219bc28632d0, но я все равно получаю ту же ошибку. Кажется, фильтр никогда не добавляется в цепочку фильтров.

Я читал много учебников и сообщений, но все они в значительной степени говорят одно и то же и не работают для меня. Должно быть что-то простое, что мне не хватает - в конце концов, вся информация доступна для Spring Security для принятия решений о авторизации. Это возможно (вероятно?) Я пропустил что-то простое здесь. Вся помощь очень ценится!

Редактировать

Я добавил следующий код в мой SecurityFilter класс для заполнения контекста Spring безопасности. Он работает, но я чувствую, что это не идеальное решение.

List<GrantedAuthority> authorities = roles.stream() 
     .map(SimpleGrantedAuthority::new) 
     .collect(Collectors.toList()); 
PreAuthenticatedAuthenticationToken auth = new PreAuthenticatedAuthenticationToken(user, "", authorities); 
auth.setDetails(new WebAuthenticationDetails(wrappedRequest)); 
auth.setAuthenticated(true); 
SecurityContextHolder.getContext().setAuthentication(auth); 

ответ

1

Проблема с настроенным поставщиком аутентификации. Вы используете PreAuthenticatedAuthenticationProvider, который возвращает существующий токен аутентификации из метода аутентификации. Поэтому в случае, если главный имеет значение null, он игнорирует запросы и позволяет другим провайдерам аутентифицировать его.

Аутентифицировать

общественности Аутентификация подлинности (аутентификации Authentication) бросает AuthenticationException Идентифицироваться данный PreAuthenticatedAuthenticationToken. Если основной объект , содержащийся в объекте аутентификации, равен нулю, запрос будет проигнорирован, чтобы позволить другим провайдерам его аутентифицировать.

В принципе, вам необходимо настроить другой AuthenticationProvider, который будет генерировать токен аутентификации и установить этот токен в SecurityContext.

+0

Но, глядя на источник J2eePreAuthenticatedProcessingFilter, он показывает, что он создает объект аутентификации из HttpRequest и помещает его в контекст безопасности (через AbstractPreAuthenticatedProcessingFilter). Разве это не все, что мне нужно? – Doughnuts

+0

Я посмотрел на источник J2eePreAuthenticatedProcessingFilter и не создал объект аутентификации. Он просто возвращает пользователя-пользователя из HttpRequest. –

+0

См. Https://github.com/spring-projects/spring-security/blob/master/web/src/main/java/org/springframework/security/web/authentication/preauth/AbstractPreAuthenticatedProcessingFilter.java (суперкласс J2eePreAuthenticatedProcessingFilter) – Doughnuts