Spring security OAuth2 authentication and form login in one app - spring

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]
}

Related

Spring Security password fails verification

I was following Spring Security articles:
[Spring Security without WebSecurityConfigurerAdapter]: https://spring.io/blog/2022/02/21/spring-security-without-the-websecurityconfigureradapter
[Spring Security Blog]: http://staging5.baeldung.com/spring-deprecated-websecurityconfigureradapter
and I keep getting the error:
o.s.s.a.dao.DaoAuthenticationProvider : Failed to authenticate since password does not match stored value
Below is my SecurityConfig class:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true,
jsr250Enabled=true)
public class WebSecurityConfig {
private static final String ROLE_ADMIN_USER = "ADMIN_USER";
private static final String ROLE_POWER_USER = "POWER_USER";
private static final String ROLE_GUEST_USER = "GUEST_USER";
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
UserDetails user1 = User.withUsername("user1")
.password(passwordEncoder().encode("user1abc"))
.roles(ROLE_ADMIN_USER).build();
UserDetails user2 = User.withUsername("user2")
.password(passwordEncoder().encode("user2abc"))
.roles(ROLE_POWER_USER).build();
UserDetails user3 = User.withUsername("user3")
.password(passwordEncoder().encode("user3abc"))
.roles(ROLE_GUEST_USER).build();
return new InMemoryUserDetailsManager(user1, user2, user3);
}
#Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests()
.antMatchers("/index").hasAnyRole(ROLE_ADMIN_USER, ROLE_POWER_USER, ROLE_GUEST_USER)
.antMatchers("/inventory").hasAnyRole(ROLE_ADMIN_USER, ROLE_POWER_USER)
.antMatchers("/guest").hasAnyRole(ROLE_GUEST_USER)
.antMatchers("/login*").permitAll()
.antMatchers("/doLogin").permitAll()
.antMatchers("/img/**").permitAll()
.antMatchers("/css/**").permitAll()
.antMatchers("/js/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.usernameParameter("j_username")
.passwordParameter("j_password")
.loginProcessingUrl("/doLogin")
.defaultSuccessUrl("/index", true)
.successHandler(new AuthenticationSuccessHandler() {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println("--- Login successful ---");
}
})
.failureUrl("/login");
return http.build();
}

Spring boot application with Office 365 authentication

I'm developing an application (spring boot for backend and react for frontend) with authentication with Office 365. But I want to use my own group and permissions for Users. For instance, when a User access to /api/auth for the first time, I want to retrieve informations from microsoft graph and save it to my DB and then protect my endpoint with my own roles/permissions.
So far I managed to do this :
When i go to localhost:8080 (back) i'm redirect to Azure portal to authenticate. Then, I can access to my endpoints
I can protect my endpoints with my own roles
When i go to localhost:3000 (react app) I have a button that redirect me to the portal and give me an azure access token (thanks to MSAL.js)
So my problem is that I can't validate this azure token in my backend and send a new token from the back to the front to send request (like GET /api/users or POST /api/todos). I think my backend configuration and implementation is wrong but I didn't find a way to validate tokens and return a token for my backend...
I hope I was clear, english isn't my native language
Here is my WebSecurityConfig
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/**")
.authenticated()
.and()
.csrf().csrfTokenRepository(csrfTokenRepository()).and()
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
.oauth2Login();
}
private Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
String token = csrf.getToken();
if (cookie == null || token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
};
}
#Bean
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
StrictHttpFirewall firewall = new StrictHttpFirewall();
firewall.setAllowUrlEncodedSlash(true);
return firewall;
}
#Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
web.httpFirewall(allowUrlEncodedSlashHttpFirewall());
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
}
And here's how I protect my endpoints :
#PreAuthorize("hasPermission(#foo, 'write')")
The conf :
#Configuration
public class AclPermissionEvaluator implements PermissionEvaluator {
#Autowired
private RoleRepository roleRepository;
#Autowired
private SecurityService securityService;
#Override
public boolean hasPermission(final Authentication authentication, final Object privilegeName, final Object privilegeType) {
DefaultOidcUser principal = (DefaultOidcUser) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
Map<String, Object> userAttributes = principal.getAttributes();
UserInfo userInfo = securityService.getUserInfoByLogin((String) userAttributes.get("unique_name"));
if (userInfo == null || StringUtils.isBlank((CharSequence) privilegeName) || StringUtils.isBlank((CharSequence) privilegeType)) {
return false;
}
for (Permission permission : roleRepository.getByName(userInfo.getRoleName()).getPermissions()) {
if (permission.getPermission().startsWith((String) privilegeName) || permission.getPermission().equals("*")) {
return true;
}
}
return false;
}
//We don't need an implementation of this function for now
#Override
public boolean hasPermission(final Authentication authentication, final Serializable serializable, final String s, final Object o) {
return false;
}
}
Security Service :
#Service
#Transactional
public class SecurityServiceImpl implements SecurityService {
#Autowired private UserRepository userRepo;
#Autowired
private RoleRepository roleRepository;
#Override
public UserInfo getUserInfoByLogin(String username) {
User user = userRepo.getUserByUsername(username);
ModelMapper modelMapper = new ModelMapper();
return modelMapper.map(user, UserInfo.class);
}
}
RoleRepository :
#Repository
public interface RoleRepository extends JpaRepository<Role, Long> {
public Role getByName(String name);
}
And on my application.yml :
spring:
security:
oauth2:
client:
registration:
azure:
clientId: <my-clientId>
clientSecret: <my-secret>
azure:
activedirectory:
tenant-id: <my-tenant-id>
user-group:
allowed-groups: all
active-directory-groups: all
you can use similar to the below code
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
#Import(SecurityProblemSupport.class)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final CorsFilter corsFilter;
private final SecurityProblemSupport problemSupport;
private final OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService;
public SecurityConfiguration(CorsFilter corsFilter, SecurityProblemSupport problemSupport, OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService) {
this.corsFilter = corsFilter;
this.problemSupport = problemSupport;
this.oidcUserService = oidcUserService;
}
#Override
public void configure(WebSecurity web) {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/app/**/*.{js,html}")
.antMatchers("/i18n/**")
.antMatchers("/content/**")
.antMatchers("/swagger-ui/index.html")
.antMatchers("/test/**");
}
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.csrf()
.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.addFilterBefore(corsFilter, CsrfFilter.class)
.exceptionHandling()
.accessDeniedHandler(problemSupport)
.and()
.headers()
.contentSecurityPolicy("default-src 'self'; frame-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://storage.googleapis.com; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:")
.and()
.referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)
.and()
.featurePolicy("geolocation 'none'; midi 'none'; sync-xhr 'none'; microphone 'none'; camera 'none'; magnetometer 'none'; gyroscope 'none'; speaker 'none'; fullscreen 'self'; payment 'none'")
.and()
.frameOptions()
.deny()
.and()
.authorizeRequests()
.antMatchers("/api/auth-info").permitAll()
.antMatchers("/api/**").authenticated()
.antMatchers("/management/health").permitAll()
.antMatchers("/management/info").permitAll()
.antMatchers("/management/prometheus").permitAll()
.antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
.and()
.oauth2Login()
.userInfoEndpoint()
.oidcUserService(oidcUserService);
// #formatter:on
}
/**
* Map authorities from "groups" or "roles" claim in ID Token.
*
* #return a {#link GrantedAuthoritiesMapper} that maps groups from
* the IdP to Spring Security Authorities.
*/
#Bean
public GrantedAuthoritiesMapper userAuthoritiesMapper() {
return (authorities) -> {
Set<GrantedAuthority> mappedAuthorities = new HashSet<>();
authorities.forEach(authority -> {
mappedAuthorities.addAll(authorities);
});
return mappedAuthorities;
};
}
}
you need to change the userAuthoritiesMapper method to achieve what you looking for
extra configuration
spring security config
spring:
security:
oauth2:
client:
registration:
azure:
client-id: <<CLIENT_ID>>
client-secret: <<CLIENT_SECRET>>
Azur Active directory config
azure:
activedirectory:
tenant-id: <<YOUR_TENANT_ID>>
active-directory-groups: Users
b2c:
reply-url: http://localhost:9000 # should be absolute url.
logout-success-url: http://localhost:9000
I'll give a secret whenever you stuck in any of the spring boot configurations go and find how jhipster make it
you can find more information by visiting this article posted by jhipster creator
NOTE: SecurityProblemSupport is a library implemented by zalando
finally the code posted copied from this repo

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

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

successForwardUrl does not work with Spring Social after authenticating successfully

I'm working on a Spring Boot project integrating with Spring Social. After authenticating with google successfully, I want to redirect to the end point /userInfo, but it seems to redirect to the previous page where I make a request to authenticate to Google: http://localhost:8080/auth/google
I've also tried to create a bean CustomAuthenticationSuccessHandler, which implements the AuthenticationSuccessHandler and add that to the configuration file, but it didn't work either
My WebSecurityConfiguration:
#Configuration
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
DataSource dataSource;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
// This bean is load the user specific data when form login is used.
#Override
public UserDetailsService userDetailsService() {
return userDetailsService;
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
// Enable jdbc authentication
#Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication()
.dataSource(dataSource)
.passwordEncoder(passwordEncoder())
.usersByUsernameQuery("select user_name, encryted_password"
+ " from app_user where user_name=?");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// Pages do not require login
http.authorizeRequests()
.antMatchers("/", "/signup", "/login", "/logout")
.permitAll();
http.authorizeRequests()
.antMatchers("/user/**")
.access("hasRole('" + AppRole.ROLE_USER + "')");
// For ADMIN only.
http.authorizeRequests()
.antMatchers("/admin/**")
.access("hasRole('" + AppRole.ROLE_ADMIN + "')");
// When the user has logged in as XX.
// But access a page that requires role YY,
// AccessDeniedException will be thrown.
http.authorizeRequests()
.and()
.exceptionHandling()
.accessDeniedPage("/403");
// Form Login config
http.authorizeRequests()
.and()
.formLogin()
.loginProcessingUrl("/j_spring_security_check") // the url to submit the username and password to
.loginPage("/login") // the custom login page
.successForwardUrl("/userInfo") // the landing page after a successful login
.failureUrl("/login?error=true") // the landing page after an unsuccessful login
.usernameParameter("username")
.passwordParameter("password");
// Logout Config
http.authorizeRequests()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/logoutSuccessful");
http.apply(new SpringSocialConfigurer())
.signupUrl("/signup");
}
}
MyController:
#RestController
#Transactional
public class MainController {
#Autowired
private AppUserDAO appUserDAO;
#Autowired
private ConnectionFactoryLocator connectionFactoryLocator;
#Autowired
private UsersConnectionRepository userConnectionRepository;
#Autowired
private AppUserValidator appUserValidator;
#RequestMapping(value = {"/", "/welcome"}, method = RequestMethod.GET)
public String welcomePage(Model model) {
model.addAttribute("title", "Welcome");
model.addAttribute("message", "This is welcome page!");
return "welcomePage";
}
#RequestMapping(value = "/logoutSuccessful", method = RequestMethod.GET)
public String logoutSuccessfulPage(Model model) {
model.addAttribute("title", "Logout");
return "logoutSuccessfulPage";
}
#RequestMapping(value = "/userInfo", method = RequestMethod.GET)
public String userInfo(Model model, Principal principal) {
// After user login successfully.
String userName = principal.getName();
System.out.println("User Name: " + userName);
UserDetails loginedUser = (UserDetails) ((Authentication) principal).getPrincipal();
String userInfo = WebUtils.toString(loginedUser);
model.addAttribute("userInfo", userInfo);
return "userInfoPage";
}
Are there any ways to forward to /userInfo url after logging in with Spring Social ?
Try in POST "/userInfo" return "redirect:/userInfoPage".

spring OAuth2 zuul--Access token expired,invalid_token

I have a spring zuul OAuth2 app.
authServer--
OAuth2ServerConfiguration:
#Configuration
public class {
#Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends
ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID);
}
#Override
public void configure(HttpSecurity http) throws Exception { http .authorizeRequests()
.antMatchers( "/oauth/authorize/**","/oauth/check_token/**").permitAll()
.anyRequest().authenticated();
// #formatter:on
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends
AuthorizationServerConfigurerAdapter {
//private TokenStore tokenStore = new InMemoryTokenStore();
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Autowired
TokenStore tokenStore;
#Autowired
private CustomUserDetailService customUserDetailService;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
// #formatter:off
endpoints
.tokenStore(this.tokenStore)
.authenticationManager(this.authenticationManager)
.userDetailsService(customUserDetailService);
// #formatter:on
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// #formatter:off
clients
.inMemory()
.withClient("kksdi2388wmkwe")
.authorizedGrantTypes("authorization_code","password", "refresh_token")
.scopes("read", "write")
.resourceIds("ReadAndWriteResource")
.secret("kksd23isdmsisdi2")
.autoApprove(true)
.accessTokenValiditySeconds(120)
.refreshTokenValiditySeconds(1200);
// #formatter:on
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(this.tokenStore);
return tokenServices;
}
}
}
webSecurity:
#Configuration
#EnableWebSecurity
#Order(-20)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomAuthenticationProvider customAuthenticationProvider;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.authorizeRequests()
.antMatchers("/login", "/").permitAll()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.csrf().disable()
.requestMatchers().antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access")
.and()
.authorizeRequests().anyRequest().authenticated()
;
// #formatter:on
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(11);
}
}
zuul server:
security:
user:
password: none
oauth2:
client:
accessTokenUri: http://localhost:9999/uaa/oauth/token
userAuthorizationUri: http://localhost:9999/uaa/oauth/authorize
clientId: kksdi2388wmkwe
clientSecret: kksd23isdmsisdi2
resource:
userInfoUri: http://localhost:9999/uaa/user
zuul:
routes:
auth-server: /auth-server/**
resource: /resource/**
zuul app:
#SpringBootApplication
#EnableZuulProxy
#EnableOAuth2Sso
public class Application extends WebSecurityConfigurerAdapter {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.logout().permitAll()
.and().authorizeRequests()
.mvcMatchers("/login/**").permitAll()
.anyRequest().authenticated();
}
}
problem:
after logged in:
can access: AuthServer "http://localhost:8080/auth-server/uaa/user" and "http://localhost:8080/api/test"
but when access_token expired,
can oly access: "http://localhost:8080/api/test",
when accessing AuthServer "http://localhost:8080/auth-server/uaa/user" met error--
<error_description>
Access token expired: 530c9247-2331-47e3-a6c0-ed61814642f5
</error_description>
<error>invalid_token</error>
and I can't get access_token from request header,
How to resolve?
Before everything check your OAUTH server application server and your client application server time and timezone if they are separated in two different machine.
Your OAUTH Server Configuration I think has some problems. OAUTH Server itself is secured with 'BASIC ACCESS AUTHENTICATION' : https://en.wikipedia.org/wiki/Basic_access_authentication
Which works with a token on his requests headers :
'Authorization' : Basic=Base64.encode(username+' '+password).
If you miss this token then you can't access any endpoint on your OAUTH server.
Mine works fine, you can test it:
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.formLogin().loginPage("/login").permitAll()
.and().requestMatchers().antMatchers("/login", "/oauth/authorize", "/oauth/confirm_access", "/fonts/**", "/css/**")
.and().authorizeRequests().antMatchers("/fonts/**", "/css/**").anonymous().anyRequest().authenticated();
// #formatter:on
}
And why have you disabled csrf protection?
these are my token store configuration :
#Autowired
#Qualifier("datasource")
private DataSource dataSource;
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Bean
protected AuthorizationCodeServices authorizationCodeServices() {
return new JdbcAuthorizationCodeServices(dataSource);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer)
throws Exception {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.authorizationCodeServices(authorizationCodeServices())
.authenticationManager(authenticationManager).tokenStore(tokenStore())
.approvalStoreDisabled();
}

Resources