Not granted any authorities error while authenticating user via Spring security ldap - spring-boot

I am trying to authenticate user via LDAP server using spring boot for which I have confiured LDAP successfully. Now, while I am authenticatig user credentials using authenticationManager(), I am getting not granted any authorities error.
I have tried several code but didn't find any suitable solution or may be I am missing some important point for this whole authentication process.
Controller:
#RequestMapping(value = "/login", method = RequestMethod.POST)
// public ResponseEntity<?> authenticateUser(#Valid #RequestBody LoginRequest loginRequest, BindingResult result){
public ResponseEntity<?> authenticateUser(#Valid #ModelAttribute LoginRequest loginRequest, BindingResult result){
ResponseEntity<?> errorMap = mapValidationErrorService.getMapValidationErrors(result);
if(errorMap != null) return errorMap;
String jwt = null;
try {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()) );
System.out.println("test : "+authentication.toString());
SecurityContextHolder.getContext().setAuthentication(authentication);
jwt = TOKEN_PREFIX + tokenProvider.generateToken(authentication);
}catch (Exception e) {
return new ResponseEntity<>("Not Authorized", HttpStatus.FORBIDDEN);
}
Security Config
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${ldap-url}")
private String url;
#Value("${ldap-basedn}")
private String baseDn;
#Value("${ldap-user-password}")
private String userPassword;
#Value("${ldap-user-dnpattern}")
private String userDnPattern;
#Value("${ldap.password}")
private String ldapPrincipalPassword;
#Value("${ldap.username}")
private String ldapSecurityPrincipal;
#Autowired
private JwtAuthenticationEntryPoint unauthorizedhandler;
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
#Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() { return new JwtAuthenticationFilter();}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.userDnPatterns(userDnPattern)
.contextSource()
.url(url+baseDn)
.managerDn(ldapSecurityPrincipal)
.managerPassword(ldapPrincipalPassword)
.and()
.passwordCompare()
.passwordEncoder(new LdapShaPasswordEncoder())
.passwordAttribute("userPassword");
// super.configure(auth);
// auth.userDetailsService(customUserDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
#Override
#Bean(BeanIds.AUTHENTICATION_MANAGER)
protected AuthenticationManager authenticationManager() throws Exception {
// TODO Auto-generated method stub
return super.authenticationManager();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors();
http.csrf().disable()
.exceptionHandling().authenticationEntryPoint(null).and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.headers().frameOptions().sameOrigin()
.and()
.authorizeRequests()
.antMatchers(
"/",
"favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js"
).permitAll()
.antMatchers("/api/users/**").permitAll()
.anyRequest().fullyAuthenticated();
// .antMatchers(SIGN_UP_URLS).permitAll()
// .anyRequest()
// .authenticated();
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
super.configure(http);
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
return bCryptPasswordEncoder;
}
}
Authentication result is:
test : org.springframework.security.authentication.UsernamePasswordAuthenticationToken#58d6c26a: Principal: org.springframework.security.ldap.userdetails.LdapUserDetailsImpl#a7293dae: Dn: mail=email#gmail.com,ou=projectName,o=companyName; Username: email#gmail.com; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; CredentialsNonExpired: true; AccountNonLocked: true; Not granted any authorities; Credentials: [PROTECTED]; Authenticated: true; Details: null; Not granted any authorities
Please help me out with this. How to avoid not granted authorities error.
Thanks in advance!

Update security config class instead of First configure method (AuthenticationManagerBuilder) use:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication()
.userDnPatterns(userDnPattern)
.contextSource()
.url(url+baseDn)
.managerDn(ldapSecurityPrincipal)
.managerPassword(ldapPrincipalPassword)
.and()
.ldapAuthoritiesPopulator(myAuthPopulator);
}
Also, autowire LdapAuthoritiesPopulator

Related

Is there a different manner to do the authentication with the new spring security using jwt?

I try to do the security of my project adapting the baeldung documentation and the previous code, and I want to know the normal method of this. I have the following configuration
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig {
#Autowired
private UserDetailsService customUserDetailsService;
#Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Autowired
private PasswordEncoder passwordEncoder;
#Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
#Bean
public AuthenticationManager authenticationManager(HttpSecurity httpSecurity) throws Exception{
return httpSecurity.getSharedObject(AuthenticationManagerBuilder.class)
.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder)
.and()
.build();
}
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.cors()
.and()
.exceptionHandling()
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/user/create", "/api/login", "/swagger-ui/**", "/v3/api-docs/**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.httpBasic();
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
then I have this token provider
#Component
public class JtwTokenProvider {
#Value("${app.jwt-secret}")
private String jwtSecret;
#Value("${app.jwt-expiration-milliseconds}")
private int jwtExpirationInMs;
public String generateToken(Authentication authentication) {
String username = authentication.getName();
Date now = new Date();
Date expiryDate = new Date(now.getTime() + jwtExpirationInMs);
String token = Jwts.builder().setSubject(username).setIssuedAt(new Date())
.setExpiration(expiryDate).signWith(SignatureAlgorithm.HS512, jwtSecret).compact();
return token;
}
public String getUsernameOfJwt(String token){
Claims claims = Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token).getBody();
return claims.getSubject();
}
public boolean validateToken(String token){
try {
Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(token);
return true;
}catch (SignatureException e){
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid JWT signature");
}catch (MalformedJwtException e){
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Invalid JWT token");
}catch (ExpiredJwtException e){
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Expired JWT token");
}catch (UnsupportedJwtException e){
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Unsupported JWT token");
}catch (IllegalArgumentException e){
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "JWT claims string is empty");
}
}
}
The token filter is the same and this manner is okay? What others exist?
public class JwtAuthenticationFilter extends OncePerRequestFilter {
#Autowired
private JtwTokenProvider tokenProvider;
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//Get JWT from request
String token = getJwtFromRequest(request);
if (StringUtils.hasText(token) && tokenProvider.validateToken(token)) {
// Get username from token
String username = tokenProvider.getUsernameOfJwt(token);
// Load user associated with the token
UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
//Set the authentication in the SecurityContext
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request, response);
}
private String getJwtFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.replace("Bearer ", "");
}
return null;
}
}
Then I used the userdetails service
#Service
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username).orElseThrow(
() -> new NotFoundException("User not found"));
return new org.springframework.security.core.userdetails.User(user.getUsername(),
user.getPassword(), getAuthority(user.getRoles()));
}
private Collection<? extends GrantedAuthority> getAuthority(Set<Role> roles){
return roles.stream().map(role -> new SimpleGrantedAuthority(role.getName()))
.collect(Collectors.toList());
}
}
Finally here is my authentication, this is safe? what is the standart manner of do the same?
#Service
public class LoginServiceImpl implements LoginService{
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private JtwTokenProvider jwtTokenProvider;
#Override
public JwtAuthResponse login(LoginRequest loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(),
loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtTokenProvider.generateToken(authentication);
return new JwtAuthResponse(jwt);
}
}
I was waiting your responses thanks :D

Migration to Ldap based authentication from Inmemory authentication

I have to implement a LDAP based authentication and return a JWT token in response which will be used in subsequent request.
I followed this guide InMemory Authentication with JWT to implement InMemory based Authentication. I know and tried standalone code for LDAP authentication and it's working.
While integrating ldap authentication in the code explained in the above link's example,I am getting stuck and not able to move forward.
I am not getting, How to define loadByUsername method of UserDetailsService class in case of ldap authentication.
Looking for some direction/guidance on this to proceed.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class JWTWebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtUnAuthorizedResponseAuthenticationEntryPoint jwtUnAuthorizedResponseAuthenticationEntryPoint;
#Autowired
private JwtTokenAuthorizationOncePerRequestFilter jwtAuthenticationTokenFilter;
#Autowired
private Environment env;
#Value("${jwt.get.token.uri}")
private String authenticationPath;
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new LdapAuthenticationProvider(env)).eraseCredentials(false);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(jwtUnAuthorizedResponseAuthenticationEntryPoint).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.anyRequest().authenticated();
httpSecurity
.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
httpSecurity
.headers()
.frameOptions().sameOrigin() //H2 Console Needs this setting
.cacheControl(); //disable caching
}
#Override
public void configure(WebSecurity webSecurity) throws Exception {
webSecurity
.ignoring()
.antMatchers(
HttpMethod.POST,
authenticationPath
)
.antMatchers(HttpMethod.OPTIONS, "/**")
.and()
.ignoring()
.antMatchers(
HttpMethod.GET,
"/" //Other Stuff You want to Ignore
)
.and()
.ignoring()
.antMatchers("/h2-console/**/**");//Should not be in Production!
}
#Bean
#Override
public UserDetailsService userDetailsService() {
return super.userDetailsService();
}
}
#Component
public class LdapAuthenticationProvider implements AuthenticationProvider
{
private Environment environment;
public LdapAuthenticationProvider(Environment environment) {
this.environment = environment;
}
private LdapContextSource contextSource;
private LdapTemplate ldapTemplate;
private void initContext(Authentication authentication)
{ contextSource = new LdapContextSource();
contextSource.setUrl(environment.getProperty("ldap.server.url"));
//contextSource.setAnonymousReadOnly(true);
contextSource.setUserDn("domain\\uid");
contextSource.setBase("DC=global,DC=comp,DC=org");
contextSource.setPassword("pwd");
contextSource.afterPropertiesSet();
ldapTemplate = new LdapTemplate(contextSource);
ldapTemplate.setIgnorePartialResultException(true);
}
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException
{
initContext(authentication);
Filter filter = new EqualsFilter("sAMAccountName", authentication.getName());
Boolean authenticate = ldapTemplate.authenticate(LdapUtils.emptyLdapName(), filter.encode(), authentication.getCredentials().toString());
if (authenticate)
{
UserDetails userDetails = new User(authentication.getName(), authentication.getCredentials().toString()
, new ArrayList<>());
Authentication auth = new UsernamePasswordAuthenticationToken(userDetails,
authentication.getCredentials().toString(), new ArrayList<>());
return auth;
}
else
{
return null;
}
}
#Override
public boolean supports(Class<?> authentication)
{
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
#Component
public class JwtTokenAuthorizationOncePerRequestFilter extends OncePerRequestFilter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
#Autowired
private UserDetailsService JwtLdapUserDetailsService;
#Autowired
private JwtTokenUtil jwtTokenUtil;
#Value("${jwt.http.request.header}")
private String tokenHeader;
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
logger.debug("Authentication Request For '{}'", request.getRequestURL());
final String requestTokenHeader = request.getHeader(this.tokenHeader);
String username = null;
String jwtToken = null;
if (requestTokenHeader != null && requestTokenHeader.startsWith("Bearer ")) {
jwtToken = requestTokenHeader.substring(7);
try {
username = jwtTokenUtil.getUsernameFromToken(jwtToken);
} catch (IllegalArgumentException e) {
logger.error("JWT_TOKEN_UNABLE_TO_GET_USERNAME", e);
} catch (ExpiredJwtException e) {
logger.warn("JWT_TOKEN_EXPIRED", e);
}
} else {
logger.warn("JWT_TOKEN_DOES_NOT_START_WITH_BEARER_STRING");
}
logger.debug("JWT_TOKEN_USERNAME_VALUE '{}'", username);
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.JwtLdapUserDetailsService.loadUserByUsername(username);
if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
chain.doFilter(request, response);
}
}
Above are some code files (modified for ldap) in the application. Complete code (base of my changes - InMemory based auth+Jwt) is available in the link mentioned above.
Thanks,

Spring security - Custom authentication provided not called

I have read all stackoverflow topics about same issue. I have read baeldung tutorials, yet I'm still not getting this working.
My CustomAuthenticationProvider is not being called, hence I get denied access everytime.
I might be missing something obvious as I'm a Spring beginner. But I have read plenty of tutorials and I'm pretty sure I'm doing things as it is supposed to be done.
Below is my WebSecurityConfigurerAdapter :
#Configuration
#EnableWebSecurity
public class NovataxewebSecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
CustomAuthenticationProvider customAuthenticationProvider;
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/login/**")
.antMatchers("/resources/**")
.antMatchers("/sessionTimeout")
.antMatchers("/logout");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
/* I was trying to do this at the beginning, since it's not working i'm doing something simpler below
http
.csrf().disable()
.authenticationProvider(customAuthenticationProvider)
.authorizeRequests()
.antMatchers("/login*").anonymous()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/loggedIn")
.failureUrl("/loginfailed")
.and()
.logout().logoutSuccessUrl("/logout")
.deleteCookies("remove")
.invalidateHttpSession(true)
.permitAll()
.and()
.sessionManagement()
.maximumSessions(25);*/
http.authorizeRequests().anyRequest().authenticated()
.and()
.httpBasic();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
}
And here is the CustomAuthenticationProvider. I'm sure it is not going inside thanks to breakpoints inside the authenticate method.
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
private static String loginSave;
private static String passwordSave;
#Autowired
private MessageSource messageSource;
#Autowired
private UsernovaRepository usernovaRepository;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
if(name.matches("")){
throw new UsernameNotFoundException(messageSource.getMessage("utilisateur_incorrect", null, Locale.getDefault()));
}
UsernovaDAO user = null;
try {
user = usernovaRepository.findByUsername(name).get(0);
} catch (Exception e) {
throw new UsernameNotFoundException(messageSource.getMessage("utilisateur_incorrect", null, Locale.getDefault()));
}
String cryptedPass="";
try {
cryptedPass = SHA_256_motdepasse(password);
} catch (Exception e1) {
e1.printStackTrace();
}
if (user!=null && user.getPassword()==null) {
List<GrantedAuthority> grantedAuths = new ArrayList<>();
Authentication auth = new UsernamePasswordAuthenticationToken(name, password, grantedAuths);
try {
user.setPassword(SHA_256_motdepasse(password));
usernovaRepository.saveAndFlush(user);
loginSave = name;
passwordSave = password;
} catch (Exception e) {
e.printStackTrace();
}
return auth;
}else if(user!=null&& user.getPassword().equals(cryptedPass)){
loginSave = name;
passwordSave = password;
List<GrantedAuthority> grantedAuths = new ArrayList<>();
Authentication auth = new UsernamePasswordAuthenticationToken(name, password, grantedAuths);
return auth;
}
else if(user!=null&& !user.getPassword().matches(cryptedPass)){
throw new BadCredentialsException(messageSource.getMessage("mot_de_passe_incorrect", null, Locale.getDefault()));
}
else {
}
throw new UsernameNotFoundException(messageSource.getMessage("utilisateur_incorrect", null, Locale.getDefault()));
}
public String SHA_256_motdepasse(String passW) throws Exception {
// this algorithm returns a sha password
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
Also I'm using Spring Boot with Spring Security. It is an Apache Tomcat Server.

Spring Security and Token Auth for API

I've been scouring the web looking at a lot of different ways to implement token based authentication using Spring & Spring Security (SS). I'm not really wanting to go the full on Oauth route so I've been trying to do something and keep things pretty simple.
What I want is to pass a username/password to SS's built in mechanism and on success, generate a token that I pass back to the user. The user then makes all future requests with the token in a custom header. The token will expire after som length of time. I am aware this is kind of what Oauth does but again, don't want to use it.
So I've got something kind of working. I can login with username/password and get the token back. I can then make requests with the token successfully. What isn't working are authorities. Here's what I'm doing...
Custom Auth Failure Handler that simply returns HttpServletResponse.SC_UNAUTHORIZED
Custom Success Handler that simply returns HttpServletResponse.SC_OK and the token
Custom Auth Entry Point that just response with HttpServletResponse.SC_UNAUTHORIZED
Now, I also have a custom UserDetails and UserDetailsService.
public class MyUserDetails implements UserDetails {
private User user; // this is my own User object
private List<GrantedAuthority> authorities;
public MyUserDetails(User user, List<GrantedAuthority> authorities) {
this.user = user;
this.authorities = authorities;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
#Override
public String getPassword() {
return user.getPassword();
}
#Override
public String getUsername() {
return user.getUsername();
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public void setAuthorities(List<GrantedAuthority> authorities) {
this.authorities = authorities;
}
}
#Service
public class MyUserDetailsService implements UserDetailsService {
private final UserService userService;
#Autowired
public MyUserDetailsService(UserService userService) {
this.userService = userService;
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userService.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException(username);
}
List<GrantedAuthority> authorities = new ArrayList<>();
// for now, just add something
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new MyUserDetails(user, authorities);
}
}
In order to look in the header for the token and tell spring all is well, I created a AuthTokenFilter...
public class AuthTokenFilter extends UsernamePasswordAuthenticationFilter {
#Autowired
private MyUserDetailsService userDetailsService;
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String authToken = httpRequest.getHeader("X-TOKEN-AUTH");
String username = null;
if (authToken != null) {
username = Jwts.parser()
.setSigningKey("1234")
.parseClaimsJws(authToken)
.getBody()
.getSubject();
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
// TODO: validate token
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
chain.doFilter(request, response);
}
}
And this is how I've configured web security:
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private MyUserDetailsService userDetailsService;
#Autowired
private RestAuthEntryPoint authenticationEntryPoint;
#Autowired
private AuthSuccessHandler authSuccessHandler;
#Autowired
private AuthFailureHandler authFailureHandler;
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
#Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
#Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setPasswordEncoder(new ShaPasswordEncoder());
return authenticationProvider;
}
#Bean
public AuthTokenFilter authenticationTokenFilterBean() throws Exception {
AuthTokenFilter authenticationTokenFilter = new AuthTokenFilter();
authenticationTokenFilter.setAuthenticationManager(authenticationManagerBean());
return authenticationTokenFilter;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authenticationProvider(authenticationProvider())
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.formLogin()
.permitAll()
.loginProcessingUrl("/login")
.usernameParameter("username")
.passwordParameter("password")
.successHandler(authSuccessHandler)
.failureHandler(authFailureHandler)
.and()
.logout()
.permitAll()
.and()
.sessionManagement()
.maximumSessions(1);
http.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
http.authorizeRequests().anyRequest().authenticated();
}
}
Everything seems to work accept SS isn't limiting access at all. If the token is there SS just lets everything pass.
Well, after much trial and error it was as simple as adding the following to my SpringSecurityConfig
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
Kind of surprised that I didn't run into this sooner. Not sure if this is something somewhat new or what.

Spring security OAuth2 authentication and form login in one app

Is it possible to combine authoryzation and authentication by login basic and by oauth2 in one application?
My project is based on jhipster project with simple spring security session login, now i need add oauth2 security for mobile app and it's look like it is not possible.
Now i have situation when work one of them, oauth2 ok if WebSecurityConfigurerAdapter had bigger order number than ResourceServerConfiguration. That's mean if oauth security filter is first.
I read a lot in stackoverflow and try many solution like:
Spring security oauth2 and form login configuration for me thats one don't work.
Now i know that is related with some security filter conflict but i dont know how to fix it.
if someone had a similar problem and he managed to do it, or know how to get around or make it better I will be grateful for the information. Thanks in advance for your help :)
#Configuration
#EnableWebSecurity
public class SecurityOauth2Configuration extends WebSecurityConfigurerAdapter {
#Inject
private UserDetailsService userDetailsService;
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/scripts/**/*.{js,html}")
.antMatchers("/bower_components/**")
.antMatchers("/i18n/**")
.antMatchers("/assets/**")
.antMatchers("/swagger-ui/index.html")
.antMatchers("/api/register")
.antMatchers("/api/activate")
.antMatchers("/api/account/reset_password/init")
.antMatchers("/api/account/reset_password/finish")
.antMatchers("/test/**");
}
#Configuration
#EnableAuthorizationServer
public static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private static final String OAUTH_SECURITY = "jhipster.security.authentication.oauth.";
private static final String CLIENTID = "clientid";
private static final String SECRET = "secret";
private static final String TOKEN_VALIDATION_TIME = "tokenValidityInSeconds";
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("isAnonymous() || hasAuthority('"+AuthoritiesConstants.USER+"')").checkTokenAccess("hasAuthority('"+AuthoritiesConstants.USER+"')");
}
#Inject
private Environment env;
#Inject
private DataSource dataSource;
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient(env.getProperty(OAUTH_SECURITY + CLIENTID))
.scopes("read", "write")
.authorities(AuthoritiesConstants.ADMIN, AuthoritiesConstants.USER)
.authorizedGrantTypes("password", "refresh_token")
.secret(env.getProperty(OAUTH_SECURITY + SECRET))
.accessTokenValiditySeconds(env.getProperty(OAUTH_SECURITY + TOKEN_VALIDATION_TIME, Integer.class, 18000));
}
}
#Configuration
#Order(1)
public static class SecurityWebConfiguration extends WebSecurityConfigurerAdapter {
#Inject
private Environment env;
#Inject
private AjaxAuthenticationSuccessHandler ajaxAuthenticationSuccessHandler;
#Inject
private AjaxAuthenticationFailureHandler ajaxAuthenticationFailureHandler;
#Inject
private AjaxLogoutOauthSuccessHandler ajaxLogoutSuccessHandler;
#Inject
private RememberMeServices rememberMeServices;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable().authorizeRequests()
.and()
.formLogin()
.loginProcessingUrl("/api/authentication")
.successHandler(ajaxAuthenticationSuccessHandler)
.failureHandler(ajaxAuthenticationFailureHandler)
.usernameParameter("j_username")
.passwordParameter("j_password")
.permitAll()
.and()
.rememberMe()
.rememberMeServices(rememberMeServices)
.key(env.getProperty("jhipster.security.rememberme.key"))
.and()
.logout()
.logoutUrl("/api/logout")
.logoutSuccessHandler(ajaxLogoutSuccessHandler)
.deleteCookies("JSESSIONID")
.permitAll()
.and()
.exceptionHandling()
;
}
}
#Order(2)
#Configuration
#EnableResourceServer
public static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Inject
private Http401UnauthorizedEntryPoint authenticationEntryPoint;
#Inject
private AjaxLogoutOauthSuccessHandler ajaxLogoutSuccessHandler;
#Override
public void configure(HttpSecurity http) throws Exception {
ContentNegotiationStrategy contentNegotiationStrategy = http.getSharedObject(ContentNegotiationStrategy.class);
if (contentNegotiationStrategy == null) {
contentNegotiationStrategy = new HeaderContentNegotiationStrategy();
}
MediaTypeRequestMatcher preferredMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy,
MediaType.APPLICATION_FORM_URLENCODED,
MediaType.APPLICATION_JSON,
MediaType.MULTIPART_FORM_DATA);
http
.authorizeRequests()
.and()
.anonymous()
.disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic()
.and()
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.defaultAuthenticationEntryPointFor(authenticationEntryPoint, preferredMatcher)
.and()
.authorizeRequests()
.antMatchers("/api/**").fullyAuthenticated();
}
}
}
For this settings WebSecurityConfigurerAdapter session work correctly. For OAuth after correctly authorizatization i get valid acces token, but for request with this token from session i get this result:
public static String getCurrentLogin() {
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
UserDetails springSecurityUser = null;
String userName = null;
if(authentication != null) {
if (authentication.getPrincipal() instanceof UserDetails) {
springSecurityUser = (UserDetails) authentication.getPrincipal();
userName = springSecurityUser.getUsername();
} else if (authentication.getPrincipal() instanceof String) {
userName = (String) authentication.getPrincipal();
}
}
System.out.println(userName); // show anonymousUser
System.out.println(authentication.isAuthenticated()); //show true
System.out.println(authentication.getAuthorities()); //show [ROLE_ANONYMOUS]
System.out.println(userName); //show anonymousUser
return userName;
}
function write in console:
anonymousUser
true
[ROLE_ANONYMOUS]
anonymousUser
and should be user1
true
[ROLE_USER]
user1
The apps git urls:
https://github.com/rynkowsw/oauth2 it is oauth2 app
https://github.com/rynkowsw/web-and-oauth2-security this is web and oauth2 security app
This app are adapted from jhipster.github.io
to run app you need have postgres db in localhost, like in db resource file:
driver-class-name: org.postgresql.ds.PGSimpleDataSource
url: jdbc:postgresql://localhost:5432/gymapp
name: gymapp
serverName: localhost:5432
username: postgres
password: jaja
To test app the fastest way is:
http://localhost:8080/oauth/token
headers: Authorization: Basic amhpcHN0ZXJhcHA6bXlTZWNyZXRPQXV0aFNlY3JldA==
this string after basic is combination default jhispter oauth secret and clientid base64 encrypt result
then
http://localhost:8080/api/account
headers: Authorization: bearer [token from response in first request]
For this same db, result for oauth are:
for oauth2 app
{
login: "user"
password: null
firstName: "User"
lastName: "User"
email: "user#localhost"
activated: true
langKey: "en"
authorities: [1]
0: "ROLE_USER"
-
}
for web + oauth2 security:
{
login: "anonymousUser"
password: null
firstName: "Anonymous"
lastName: "User"
email: "anonymous#localhost"
activated: true
langKey: "en"
authorities: [0]
}

Resources