Spring 4 autowire to Filter - spring

I build app with Spring 4.1.6, I have all config in java class. My AppConfig:
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = "pl.wrweb.springrest")
public class AppConfig extends WebMvcConfigurerAdapter {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Bean(name = "messageSource")
public ReloadableResourceBundleMessageSource getMessageSource() {
ReloadableResourceBundleMessageSource resource = new ReloadableResourceBundleMessageSource();
resource.setBasename("classpath:messages");
resource.setDefaultEncoding("UTF-8");
return resource;
}
}
AppInitializer:
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(AppConfig.class);
ctx.setServletContext(container);
ServletRegistration.Dynamic servlet = container.addServlet("dispatcher", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");
container.addFilter("customFilter", new DelegatingFilterProxy(new CustomFilter())).addMappingForUrlPatterns(null, true, "/*");
}
#Override
protected String[] getServletMappings() {
return new String[0];
}
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[0];
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[0];
}
}
and my CustomFilter:
#Configuration
#EnableWebSecurity
public class CustomFilter implements Filter {
#Autowired
UserService userService;
public void init(FilterConfig fc) throws ServletException {
}
public void doFilter(ServletRequest req, ServletResponse res, FilterChain fc) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (httpServletRequest.getRequestURI().contains("/employee/")) {
String token = httpServletRequest.getHeader("x-token");
System.out.println("token " + token);
Long userId = TokenUtils.getUserNameFromToken(token);
System.out.println("ObjectStore.token " + ObjectStore.token);
if (token!=null) {
if (token.equals(String.valueOf(ObjectStore.token))) {
int index = ObjectStore.token++;
ObjectStore.token = index+1;
System.out.println("index " +ObjectStore.token + "token " + token);
response.setHeader("x-token", String.valueOf(ObjectStore.token));
fc.doFilter(req, response);
} else {
response.sendError(HttpStatus.FORBIDDEN.value());
fc.doFilter(req, response);
return;
}
} else {
response.sendError(HttpStatus.FORBIDDEN.value());
fc.doFilter(req, response);
return;
}
} else {
fc.doFilter(req, res);
}
}
public void destroy() {
}
}
Everything works fine but I can't inject userService and it's null, I need this to check token in request.

You should use Code as this!
private UserService userService;
and then add this code
public void init(FilterConfig fc) throws ServletException {
ApplicationContext app = WebApplicationContextUtils.getRequiredWebApplicationContext(fc.getServletContext());
userService= app.getBean(UserService.class);
}

Related

per-authentication exceptions are not triggers

I have implemented the pre authentication class and working fine, when authentication success, but when custom exception throw error not displays but redirects to the login page. I want to redirect to the error page when custom exception occurred. I used spring security auth2 and spring boot to develop it.
public class CustomPreAuthenticatedAuthenticationProvider extends PreAuthenticatedAuthenticationProvider {
private static final Logger LOG = Logger.getLogger(CustomPreAuthenticatedAuthenticationProvider.class);
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
LOG.info("CustomPreAuthenticatedAuthenticationProvider");
UmUser user = null;
String name = authentication.getName();
// String password = authentication.getCredentials().toString();
// String hashedPwd =null;
user = commonApiCallsService.callUserManagementService(name);
if (null == user) {
throw new CustomException(DataConfig.RES_CODE_INTERNAL_ERROR, name + " User not exist.");
}
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), null, translate(user.getRoles()));
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
return authenticationToken;
}
private Collection << ? extends GrantedAuthority > translate(List < Role > roles) {
List < GrantedAuthority > authorities = new ArrayList < > ();
if (null != roles) {
roles.stream().map((role) - > role.getRoleName().toUpperCase()).map((name) - > {
if (!name.startsWith("ROLE_")) {
name = "ROLE_" + name;
}
return name;
}).forEachOrdered((name) - > {
authorities.add(new SimpleGrantedAuthority(name));
});
}
return authorities;
}
}
#Configuration
#Order(1)
#EnableResourceServer
public class ResourceServerInternal extends WebSecurityConfigurerAdapter {
public ResourceServerInternal() {
super();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.antMatcher("/internal/**")
.addFilterAfter(siteminderFilter(), RequestHeaderAuthenticationFilter.class)
.authorizeRequests()
.antMatchers("/", "/internal/login*", "/callback/", "/oauth/authorize*", "/exit", "**/logout").permitAll()
.anyRequest().authenticated();
}
#Bean
public FilterRegistrationBean registration(RequestHeaderAuthenticationFilter filter) throws Exception {
FilterRegistrationBean registration = new FilterRegistrationBean(filter);
registration.setEnabled(false);
return registration;
}
#Bean(name = "siteminderFilter")
public RequestHeaderAuthenticationFilter siteminderFilter() throws Exception {
RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter = new RequestHeaderAuthenticationFilter();
requestHeaderAuthenticationFilter.setPrincipalRequestHeader("SM_USER");
requestHeaderAuthenticationFilter.setAuthenticationManager(authenticationManager());
return requestHeaderAuthenticationFilter;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.parentAuthenticationManager(authenticationManager());
}
#Bean
#Override
protected AuthenticationManager authenticationManager() throws Exception {
final List < AuthenticationProvider > providers = new ArrayList < > (1);
providers.add(preauthAuthProvider());
return new ProviderManager(providers);
}
#Bean(name = "preAuthProvider")
PreAuthenticatedAuthenticationProvider preauthAuthProvider() throws Exception {
CustomPreAuthenticatedAuthenticationProvider provider = new CustomPreAuthenticatedAuthenticationProvider();
provider.setPreAuthenticatedUserDetailsService(userDetailsServiceWrapper());
return provider;
}
#Bean
UserDetailsByNameServiceWrapper < PreAuthenticatedAuthenticationToken > userDetailsServiceWrapper() throws Exception {
UserDetailsByNameServiceWrapper < PreAuthenticatedAuthenticationToken > wrapper = new UserDetailsByNameServiceWrapper < > ();
wrapper.setUserDetailsService(userDetailsService);
return wrapper;
}
#Override
#Order(1)
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/*.css");
web.ignoring().antMatchers("/*.js");
web.ignoring().antMatchers("/css/**");
}
}
public class CustomException extends AuthenticationException {
private Integer errorCode;
private String errorMsg;
public CustomException(Integer errorCode, String errorMsg) {
super(errorMsg);
this.errorCode = errorCode;
this.errorMsg = errorMsg;
}
public Integer getErrorCode() {
return errorCode;
}
public void setErrorCode(Integer errorCode) {
this.errorCode = errorCode;
}
public String getErrorMsg() {
return errorMsg;
}
public void setErrorMsg(String errorMsg) {
this.errorMsg = errorMsg;
}
}
I have added `requestHeaderAuthenticationFilter.setContinueFilterChainOnUnsuccessfulAuthentication(false);`
to the siteminderFilter.it works.
#Bean(name = "siteminderFilter")
public RequestHeaderAuthenticationFilter siteminderFilter() throws Exception {
RequestHeaderAuthenticationFilter requestHeaderAuthenticationFilter = new RequestHeaderAuthenticationFilter();
requestHeaderAuthenticationFilter.setPrincipalRequestHeader("user_employee_id");
requestHeaderAuthenticationFilter.setAuthenticationManager(authenticationManager());
requestHeaderAuthenticationFilter.setContinueFilterChainOnUnsuccessfulAuthentication(false);
return requestHeaderAuthenticationFilter;
}

Shared SecurityContextHolder across multiple WebSecurityConfigurerAdapters

Context: I'm writing a web app that is meant to serve two different API's, each with their own authentication filter. Both filters process and authenticate JWT tokens, however the tokens themselves contain different payloads and come from different authentication sources. Also, even though the tokens are different, and come from different sources, they share the same credentials for logging in, and are secured using the same key.
Ie: You could go to either one of these auth urls, with the same credentials and get back a different JWT token, with entirely different payloads.
/auth/auth1/login
/auth/auth2/login
Problem: The problem I am encountering is that if I authenticate to one of them, I have access to the other. Even without providing a token.
Meaning if I go to /requests/something, authenticate using a bearer token from auth provider 1, then go to /ims/oneroster/v1p1/somethingElse (without passing in a different token from auth provider 2) I am able to access data, even though I haven't authenticated using the filter associated with that path.
At the moment, the only way I know of to make sure that each filter is correctly checking if the user's token is valid is to put SecurityContextHolder.clearContext(); at the top of each of the filters doFilterInternal method. However, I'm pretty sure I shouldn't be doing that.
Can anyone see a problem with what I have below, or make some recommendations?
SecurityConfig.class
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
//https://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html#multiple-httpsecurity
#Configuration #Order(1)
public static class XPressWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
private final CacheService cacheService;
public XPressWebSecurityConfigurationAdapter(CacheService cacheService) {this.cacheService = cacheService;}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/requests/**")
.authorizeRequests().anyRequest().authenticated()
.and()
.addFilter(new JWTAuthorizationFilter(authenticationManagerBean(), cacheService))
//.exceptionHandling().authenticationEntryPoint(new JWTAuthenticationEntryPoint())
;
}
}
#Configuration #Order(2)
public static class OneRosterWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
private final CacheService cacheService;
public OneRosterWebSecurityConfigurationAdapter(CacheService cacheService) {this.cacheService = cacheService;}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/ims/oneroster/v1p1/**")
.authorizeRequests().anyRequest().authenticated()
.and().addFilter(new OneRosterAuthorizationFilter(authenticationManagerBean(), cacheService))
;
}
}
}
OneRosterAuthorizationFilter.class
public class OneRosterAuthorizationFilter extends BasicAuthenticationFilter {
private final CacheService cacheService;
public OneRosterAuthorizationFilter(AuthenticationManager authManager, CacheService cacheService) {
super(authManager);
this.cacheService = cacheService;
}
#Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
logger.debug("GOING TO ONEROSTER FILTER");
AuthRequest authRequest = new AuthRequest(req);
if(authRequest.isAuthEnabled()) {
if(authRequest.isHeader() || (authRequest.isParameter() && authRequest.isAllowTokenParameter())) {
UsernamePasswordAuthenticationToken authentication = getAuthentication(req, authRequest);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
chain.doFilter(req, res);
}
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest req, AuthRequest authRequest) {
if(StringUtils.isBlank(authRequest.getToken())) {
return null; //Token was blank... 403 Forbidden
}
DecodedToken decodedToken = TokenDecoder.decodeToken(authRequest.getToken());
Application application = null;
if(decodedToken != null) {
application = new Application(decodedToken.getAppId(), decodedToken.getToken(), cacheService);
}
try {
if(!System.getenv("provider_id").equalsIgnoreCase(decodedToken.getProviderId())) {
throw new JWTVerificationException("Provider Ids Don't Match....");
}
if(application != null && StringUtils.isNotBlank(application.getApp().getProviderSecret())) {
JWT.require(Algorithm.HMAC256(application.getApp().getProviderSecret().getBytes()))
.withIssuer(PropertiesLoader.getInstance().getProperty("security.auth.jwt.issuer"))
.build().verify(authRequest.getToken());
return new UsernamePasswordAuthenticationToken(application, decodedToken.getToken(), getACLs(application));
}
}
catch (JWTVerificationException exception) {
//https://medium.com/fullstackblog/spring-security-jwt-token-expired-custom-response-b85437914b81
req.setAttribute("JWTVerificationException", exception.getMessage());
return null;
}
return null; //DecodedToken or Application was null... 403 Forbidden
}
private Collection<GrantedAuthority> getACLs(Application application) {
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();
application.getPermissions().forEach(pathPermission -> {
if(pathPermission.getGet()) {
grantedAuthorities.add(new SimpleGrantedAuthority("get:" + pathPermission.getPath()));
}
if(pathPermission.getPost()) {
grantedAuthorities.add(new SimpleGrantedAuthority("post:" + pathPermission.getPath()));
}
if(pathPermission.getPut()) {
grantedAuthorities.add(new SimpleGrantedAuthority("put:" + pathPermission.getPath()));
}
if(pathPermission.getDelete()) {
grantedAuthorities.add(new SimpleGrantedAuthority("delete:" + pathPermission.getPath()));
}
});
return grantedAuthorities;
}
}
JWTAuthorizationFilter.class
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
private final CacheService cacheService;
public JWTAuthorizationFilter(AuthenticationManager authManager, CacheService cacheService) {
super(authManager);
this.cacheService = cacheService;
}
#Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
logger.debug("GOING TO JWT FILTER");
AuthRequest authRequest = new AuthRequest(req);
if(authRequest.isAuthEnabled()) {
if(authRequest.isHeader() || (authRequest.isParameter() && authRequest.isAllowTokenParameter())) {
UsernamePasswordAuthenticationToken authentication = getAuthentication(req, authRequest);
if(authentication != null) {
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}
chain.doFilter(req, res);
}
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest req, AuthRequest authRequest) {
if(StringUtils.isBlank(authRequest.getToken())) {
return null; //Token was blank... 403 Forbidden
}
DecodedToken decodedToken = TokenDecoder.decodeToken(authRequest.getToken());
Application application = null;
if(decodedToken != null) {
application = new Application(decodedToken.getApplication_id(), decodedToken.getToken(), cacheService);
}
try {
if(application != null && StringUtils.isNotBlank(application.getApp().getProviderSecret())) {
JWT.require(Algorithm.HMAC256(application.getApp().getProviderSecret().getBytes()))
.withIssuer(PropertiesLoader.getInstance().getProperty("security.auth.jwt.issuer"))
.build().verify(authRequest.getToken());
return new UsernamePasswordAuthenticationToken(application, decodedToken.getToken(), getACLs(application));
}
}
catch (JWTVerificationException exception) {
//https://medium.com/fullstackblog/spring-security-jwt-token-expired-custom-response-b85437914b81
req.setAttribute("JWTVerificationException", exception.getMessage());
return null;
}
return null; //DecodedToken or Application was null... 403 Forbidden
}
private Collection<GrantedAuthority> getACLs(Application application) {
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>();
application.getPermissions().forEach(pathPermission -> {
if(pathPermission.getGet()) {
grantedAuthorities.add(new SimpleGrantedAuthority("get:" + pathPermission.getPath()));
}
if(pathPermission.getPost()) {
grantedAuthorities.add(new SimpleGrantedAuthority("post:" + pathPermission.getPath()));
}
if(pathPermission.getPut()) {
grantedAuthorities.add(new SimpleGrantedAuthority("put:" + pathPermission.getPath()));
}
if(pathPermission.getDelete()) {
grantedAuthorities.add(new SimpleGrantedAuthority("delete:" + pathPermission.getPath()));
}
});
return grantedAuthorities;
}
}
Note: Application is the class that implements UserDetails
After reading a comment from dur, here is the resolution to my problem. All I needed to do was add:
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
to each of the HttpSecurity objects.
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {
//https://docs.spring.io/spring-security/site/docs/current/reference/html/jc.html#multiple-httpsecurity
#Configuration #Order(1)
public static class XPressWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
private final CacheService cacheService;
public XPressWebSecurityConfigurationAdapter(CacheService cacheService) {this.cacheService = cacheService;}
#Override
protected void configure(HttpSecurity http) throws Exception {
//https://auth0.com/blog/implementing-jwt-authentication-on-spring-boot/
http.antMatcher("/requests/**")
.authorizeRequests().anyRequest().authenticated()
.and().addFilter(new JWTAuthorizationFilter(authenticationManagerBean(), cacheService))
.exceptionHandling().authenticationEntryPoint(new JWTAuthenticationEntryPoint())
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
#Configuration #Order(2)
public static class OneRosterWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
private final CacheService cacheService;
public OneRosterWebSecurityConfigurationAdapter(CacheService cacheService) {this.cacheService = cacheService;}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/ims/oneroster/v1p1/**")
.authorizeRequests().anyRequest().authenticated()
.and().addFilter(new OneRosterAuthorizationFilter(authenticationManagerBean(), cacheService))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
}

sprin mvc 5 rest + aouth 2 + angular 6 - oauth/token ‘Access-Control-Allow-Origin’ missing

i'm starting an app with spring mvc 5 & angular 6, when i try to get the token by sending a post request with angular it show in my browser console this message:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/gestion/oauth/token. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
this is my spring configuration :
#Configuration
#EnableAuthorizationServer
#EnableGlobalMethodSecurity(prePostEnabled = true)
#Import(ServerSecurityConfig.class)
public class AuthServerOAuth2Config extends AuthorizationServerConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private PasswordEncoder oauthClientPasswordEncoder;
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Bean
public OAuth2AccessDeniedHandler oauthAccessDeniedHandler() {
return new OAuth2AccessDeniedHandler();
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()").passwordEncoder(oauthClientPasswordEncoder);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager).userDetailsService(userDetailsService);
}
}
My Resource Server Configuration class :
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.requestMatchers().antMatchers("/api/**").and().authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/**").access("#oauth2.hasScope('write')")
.anyRequest().access("#oauth2.hasScope('read')");
}
}
This is my Web Security Configurer class:
#Configuration
#EnableWebSecurity
#Import(Encoders.class)
public class ServerSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private PasswordEncoder userPasswordEncoder;
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(userPasswordEncoder);
}
}
This my APP Initializer:
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {
AppConfig.class};
}
#Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
#Override
protected Filter[] getServletFilters() {
Filter [] filters = {new CorsFilter()};
return filters;
}
}
My Custom Filter:
public class CorsFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader("Access-Control-Allow-Origin", "*");
chain.doFilter(request, response);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void destroy() {
}
}
My angular service:
public login(credentials: any): Observable<any> {
const body = `username=${credentials.username}&password=${credentials.password}&grant_type=password&client_id=admin`;
return this.httpClient.post<any>(this.URL, body, { headers: new HttpHeaders({
'Authorization': `Basic ${btoa('admin:admin')}`,
'Content-type': 'application/x-www-form-urlencoded'
})});
}
my question is how to make Angular HttpClient send this post request to generate token
You need to define proxy.conf.json
we can do
{
"/serverapplicationName/*": {
"target": "http://localhost:8080",
"secure": false,
"logLevel":"debug",
"changeOrigin": true
}
}
and please run by npm "npm start"
Try to make highest priority to your CorsFilter implementation.
#Component
#Order(Ordered.HIGHEST_PRECEDENCE)
public class CorsFilter implements Filter {
...
}

sessionRegistry.getAllPrincipals() is empty

I trying to get all logged-in users using sessionRegistry in my Spring-MVC application, i found a lot of posts and answers on how to resolve it, but i could not fix it. I'm using configuration by annotation.
I'm new to spring mvc and i want to learn a best practice, so all comments about other configurations or about my code are welcome.
Here is my code
#Configuration
#ComponentScan(basePackages = {"com.uno"})
#Import({ SecurityConfig.class })
#EnableWebMvc
public class AppConfig extends WebMvcConfigurerAdapter {
#Bean
public TilesViewResolver tilesViewResolver() {
TilesViewResolver resolver = new TilesViewResolver();
resolver.setViewClass(TilesView.class);
resolver.setOrder(1);
return resolver;
}
#Bean
public TilesConfigurer tilesConfigurer() {
TilesConfigurer tilesConfigurer = new TilesConfigurer();
tilesConfigurer.setCompleteAutoload(true);
tilesConfigurer.setCheckRefresh(true);
return tilesConfigurer;
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**").addResourceLocations(
"/resources/");
}
#Bean
SessionFactory sessionFactory() {
org.hibernate.cfg.Configuration configuration = new org.hibernate.cfg.Configuration();
configuration.configure();
LocalSessionFactoryBuilder builder = new LocalSessionFactoryBuilder(
dataSource());
builder.scanPackages("com.uno.domain").addProperties(
configuration.getProperties());
return builder.buildSessionFactory();
}
#Bean
public DriverManagerDataSource dataSource() {
DriverManagerDataSource ds = new DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/uno");
ds.setUsername("root");
return ds;
}
#Bean
public HibernateTransactionManager transactionManager() {
return new HibernateTransactionManager(sessionFactory());
}
#Bean
UserDao userDao() {
return new UserDaoImpl();
}
#Bean
UserService userService() {
return new UserServiceImpl();
}
#Bean
RoleDao roleDao() {
return new RoleDaoImpl();
}
#Bean
RoleService roleService() {
return new RoleServiceImpl();
}
#Bean
ConnexionSucessHandler connexionSuccessHandler() {
return new ConnexionSucessHandler();
}
#Bean
PersistentTokenRepository remmeberMeTokenRepository() {
JdbcTokenRepositoryImpl db = new JdbcTokenRepositoryImpl();
db.setDataSource(dataSource());
return db;
}
/* Localization section */
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
#Bean
LocaleResolver localeResolver() {
SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
sessionLocaleResolver.setDefaultLocale(new Locale("en"));
return sessionLocaleResolver;
}
#Bean
LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
localeChangeInterceptor.setParamName("lang");
return localeChangeInterceptor;
}
#Bean
ControllerClassNameHandlerMapping controllerClassNameHandlerMapping() {
ControllerClassNameHandlerMapping controllerClassNameHandlerMapping = new ControllerClassNameHandlerMapping();
Object[] interceptors = new Object[] { localeChangeInterceptor() };
controllerClassNameHandlerMapping.setInterceptors(interceptors);
return controllerClassNameHandlerMapping;
}
#Bean
ReloadableResourceBundleMessageSource messageSource() {
ReloadableResourceBundleMessageSource reloadableResourceBundleMessageSource = new ReloadableResourceBundleMessageSource();
reloadableResourceBundleMessageSource.setBasename("resources/i18n/messages");
reloadableResourceBundleMessageSource.setDefaultEncoding("UTF-8");
return reloadableResourceBundleMessageSource;
}
/* Localization section */
#Bean
CommonsMultipartResolver filterMultipartResolver(){
return new CommonsMultipartResolver();
}
}
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("userService")
UserService userDetailsService;
#Autowired
ConnexionSucessHandler connexionSucessHandler;
#Autowired
SessionRegistry sessionRegistry;
#Autowired
PersistentTokenRepository remmeberMeTokenRepository;
#Autowired
ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlAuthenticationStrategy;
#Autowired
ConcurrentSessionFilter concurrentSessionFilter;
#Autowired
RegisterSessionAuthenticationStrategy registerSessionAuthenticationStrategy;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").antMatchers("/mailManagement/**")
.hasAnyRole("USER", "ADMIN").antMatchers("/user/**").hasAnyRole("USER", "ADMIN")
.antMatchers("/login/**").permitAll().and().formLogin().successHandler(connexionSucessHandler)
.loginPage("/login").failureUrl("/login?error").usernameParameter("username")
.passwordParameter("password").and().logout().invalidateHttpSession(true).deleteCookies("JSESSIONID")
.logoutUrl("/logout").logoutSuccessUrl("/login?logout").and().csrf().and().exceptionHandling()
.accessDeniedPage("/403").and().rememberMe().rememberMeParameter("uno-remember-me")
.rememberMeCookieName("uno-remember-me").tokenValiditySeconds(1296000)
.tokenRepository(remmeberMeTokenRepository).and().sessionManagement()
.sessionAuthenticationStrategy(concurrentSessionControlAuthenticationStrategy).maximumSessions(-1);
}
#Bean
public SessionRegistry sessionRegistry() {
return new SessionRegistryImpl();
}
#Bean
public ConcurrentSessionFilter concurrentSessionFilter(){
return new ConcurrentSessionFilter(sessionRegistry);
}
#Bean
public ConcurrentSessionControlAuthenticationStrategy concurrentSessionControlAuthenticationStrategy(){
return new ConcurrentSessionControlAuthenticationStrategy(sessionRegistry);
}
#Bean
public RegisterSessionAuthenticationStrategy registerSessionAuthenticationStrategy(){
return new RegisterSessionAuthenticationStrategy(sessionRegistry);
}
}
public class SecurityInitializer extends
AbstractSecurityWebApplicationInitializer {
#Override
protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
insertFilters(servletContext, new MultipartFilter());
}
#Override
protected boolean enableHttpSessionEventPublisher() {
return true;
}
}
public class MvcWebApplicationInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class[] getRootConfigClasses() {
return new Class[] { AppConfig.class };
}
#Override
protected Class[] getServletConfigClasses() {
return null;
}
#Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.addListener(new RequestContextListener());
super.onStartup(servletContext);
}
}
public class ConnexionSucessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
#Autowired
UserProfile userProfile;
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication auth) throws IOException,
ServletException {
RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
Collection authorities = auth.getAuthorities();
userProfile.loadUser(auth.getName());
for(GrantedAuthority grantedAuthority : authorities){
switch (grantedAuthority.getAuthority()) {
case "ROLE_ADMIN":
redirectStrategy.sendRedirect(request, response, "/admin");
break;
case "ROLE_USER":
redirectStrategy.sendRedirect(request, response, "/user");
break;
}
}
}
}
problem resolved.
I was loading the same configuration twice in both ContextLoaderListener and DispatcherServlet.

Spring Session + REST + Custom Authentication Filter(read credentials from JSON rather query param)

I'm trying to convert my rest services authentication from basic authentication to form based authentication the below code works fine(Note I've commented out custom authentication filter) if I send authentication details in url as query parameter something like this http://localhost:8080/login?username=dfdf&&password=sdsdd
However I'm not keen on sending credentials as query parameter instead I would prefer to send it as json, Hence I've created custom authentication filter. When I add the custom authentication filter, my spring session stops working. I cannot find x-auth-token field in my response header. Any suggestion how to enable spring session and custom authentication together/or may be easier way to handle json input for credentials.
#Configuration
#EnableWebSecurity
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private ObjectMapper objectMapper;
#Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
#Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception {
builder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/", "/register", "/index.html").permitAll().and().authorizeRequests()
.anyRequest().authenticated().and().requestCache().requestCache(new NullRequestCache()).and()
.formLogin().failureHandler(getRESTAuthenticationFailureHandler())
.successHandler(getRESTAuthenticationSuccessHandler()).usernameParameter("username")
.passwordParameter("password").and().exceptionHandling()
.authenticationEntryPoint(getRESTAuthenticationEntryPoint()).and()
//.addFilter(getAuthenticationFilter())
.csrf().disable();
}
#Bean
public HttpSessionStrategy httpSessionStrategy() {
return new HeaderHttpSessionStrategy();
}
#Bean
public RESTAuthenticationEntryPoint getRESTAuthenticationEntryPoint() {
return new RESTAuthenticationEntryPoint();
}
#Bean
public RESTAuthenticationSuccessHandler getRESTAuthenticationSuccessHandler() {
return new RESTAuthenticationSuccessHandler();
}
#Bean
public RESTAuthenticationFailureHandler getRESTAuthenticationFailureHandler() {
return new RESTAuthenticationFailureHandler();
}
#Bean
public AuthenticationFilter getAuthenticationFilter() {
AuthenticationFilter filter = new AuthenticationFilter();
try {
filter.setAuthenticationManager(this.authenticationManager());
} catch (Exception e) {
e.printStackTrace();
}
return filter;
}
public class RESTAuthenticationEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}
public class RESTAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
clearAuthenticationAttributes(request);
}
}
public class RESTAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
super.onAuthenticationFailure(request, response, exception);
}
}
public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final Logger LOG = LoggerFactory.getLogger(AuthenticationFilter.class);
private boolean postOnly = true;
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
String username = null;
String password = null;
UserDetails userDetails = null;
if ("application/json".equals(request.getHeader("Content-Type"))) {
userDetails = getJson(request);
if (userDetails != null) {
username = userDetails.getUsername();
}
} else {
username = obtainUsername(request);
}
if ("application/json".equals(request.getHeader("Content-Type"))) {
if (userDetails != null) {
password = userDetails.getPassword();
}
} else {
password = obtainPassword(request);
}
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
username = username.trim();
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username,
password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
private UserDetails getJson(HttpServletRequest request) {
try {
final List<String> data = IOUtils.readLines(request.getReader());
final String jsonData = data.stream().collect(Collectors.joining());
LOG.info(jsonData);
UserDetails userDetails = objectMapper.readValue(jsonData, UserDetails.class);
return userDetails;
} catch (IOException e) {
LOG.error("Failed to read data {}", e.getMessage(), e);
return null;
}
}
}
}
As suggested I've created custom filter which converts json object to request parameter and adds to HttpServletRequest, However are there any inbuilt spring security custom filters to do the same job?
#Configuration
#EnableWebSecurity
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private ObjectMapper objectMapper;
#Bean
public FilterRegistrationBean contextFilterRegistrationBean() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
CstFilter contextFilter = new CstFilter();
registrationBean.addUrlPatterns("/login");
registrationBean.setFilter(contextFilter);
registrationBean.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
return registrationBean;
}
#Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
#Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception {
builder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(getRESTAuthenticationEntryPoint())
.and()
.formLogin()
.permitAll()
.loginProcessingUrl("/login")
.failureHandler(getRESTAuthenticationFailureHandler())
.successHandler(getRESTAuthenticationSuccessHandler())
.usernameParameter("username")
.passwordParameter("password")
.and()
.logout()
.permitAll()
.logoutSuccessHandler(getRESTLogoutSuccessHandler())
.and()
.authorizeRequests()
.antMatchers("/", "/index.html")
.permitAll()
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.requestCache()
.requestCache(new NullRequestCache());
}
#Bean
public HttpSessionStrategy httpSessionStrategy() {
return new HeaderHttpSessionStrategy();
}
#Bean
public RESTAuthenticationEntryPoint getRESTAuthenticationEntryPoint() {
return new RESTAuthenticationEntryPoint();
}
#Bean
public RESTAuthenticationSuccessHandler getRESTAuthenticationSuccessHandler() {
return new RESTAuthenticationSuccessHandler();
}
#Bean
public RESTAuthenticationFailureHandler getRESTAuthenticationFailureHandler() {
return new RESTAuthenticationFailureHandler();
}
#Bean
public RESTLogoutSuccessHandler getRESTLogoutSuccessHandler() {
return new RESTLogoutSuccessHandler();
}
public class JsonConvertFilter extends HttpServletRequestWrapper {
private final Logger LOG = LoggerFactory.getLogger(JsonConvertFilter.class);
private UserDetails userDetails;
public JsonConvertFilter(HttpServletRequest request) {
super((HttpServletRequest)request);
userDetails = getJson();
}
public String getParameter(String key){
if(userDetails!=null){
if("username".equals(key)){
return userDetails.getUsername();
}
if("password".equals(key)){
return userDetails.getPassword();
}
}
System.out.println("Called wrapper");
return super.getParameter(key);
}
private UserDetails getJson() {
try {
final List<String> data = IOUtils.readLines(super.getReader());
final String jsonData = data.stream().collect(Collectors.joining());
LOG.info(jsonData);
UserDetails userDetails = objectMapper.readValue(jsonData, UserDetails.class);
return userDetails;
} catch (IOException e) {
LOG.warn("Failed to read data {}", e.getMessage(), e);
return null;
}
}
}
public class CstFilter implements Filter{
#Override
public void destroy() {
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(new JsonConvertFilter((HttpServletRequest)request), response);
}
#Override
public void init(FilterConfig arg0) throws ServletException {
}
}
public class RESTLogoutSuccessHandler implements LogoutSuccessHandler{
#Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
String uri = request.getRequestURI();
if ("logout".equals(uri)) {
response.sendError(HttpServletResponse.SC_OK, "Succesfully Logged out");
}
}
}
public class RESTAuthenticationEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().print("Unauthorizated....");
}
}
public class RESTAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
clearAuthenticationAttributes(request);
}
}
public class RESTAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
String uri = request.getRequestURI();
if ("logout".equals(uri)) {
response.sendError(HttpServletResponse.SC_OK, "Succesfully Logged out");
} else {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
"Authentication Failed: " + exception.getMessage());
}
}
}
}
For any one want to test this using jquery ajax.
/* Alerts the results */
$.ajax({
url : "login",
type : "POST",
async : false,
contentType: "application/json",
data : "{ \"username\":\""+username+"\", \"password\":\"" + password + "\"}",
success : function(data, status, request) {
alert("Success");
authtokenKey = request.getResponseHeader('x-auth-token');
},
error : function(xhr, status, error) {
alert(error);
}
});

Resources