I would like to use Spring security with OAuth and JWT tokens.
My current configurations are:
#Configuration
#EnableResourceServer
public class OAuth2ServerConfig {
#Configuration
#EnableWebSecurity
protected static class ResourceServer extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.anonymous().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler()) // handle access denied in general (for example comming from #PreAuthorization
.authenticationEntryPoint(entryPointBean()) // handle authentication exceptions for unauthorized calls.
.and()
.authorizeRequests()
// only allow this three endpoint to NOT be authenticated.
.antMatchers(HttpMethod.POST, "/users").permitAll()
.antMatchers(HttpMethod.POST, "/users/authenticate").permitAll()
.antMatchers(HttpMethod.GET, "/users/inviationCode/{code}").permitAll()
.antMatchers(HttpMethod.POST, "/**").fullyAuthenticated()
.antMatchers(HttpMethod.GET, "/**").fullyAuthenticated()
.antMatchers(HttpMethod.PUT, "/**").fullyAuthenticated()
.antMatchers(HttpMethod.DELETE, "/**").fullyAuthenticated()
.antMatchers(HttpMethod.OPTIONS, "/**").fullyAuthenticated()
.and()
.addFilterBefore(filterBean(), AbstractPreAuthenticatedProcessingFilter.class)
.requestMatcher(new NegatedRequestMatcher(new AntPathRequestMatcher("/oauth/**")))
.authorizeRequests().anyRequest().authenticated().expressionHandler(new OAuth2WebSecurityExpressionHandler())
.and()
.csrf().disable(); // for chrome/FF plugins to work. for now we shouldn't face any problem since there is no point that JS can be injected into our page...
// #formatter:on
}
#Bean(name="authenticationManager")
#Override
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManagerBean();
}
#Bean
#Autowired
AccessDeniedHandler accessDeniedHandler() {
return new AccessDeniedExceptionHandler();
}
#Bean
#Autowired
AuthenticationEntryPoint entryPointBean() {
return new UnauthorizedEntryPoint();
}
#Bean
#Autowired
GenericFilterBean filterBean() {
return new XAuthTokenFilter();
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean(name="userAuthenticationManager")
public UserAuthenticationService userAuthenticationManager() throws Exception {
return new UserAuthenticationService();
}
}
#Configuration
#EnableAuthorizationServer
public static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Autowired
#Qualifier("authenticationManager")
private AuthenticationManager authenticationManager;
#Autowired
#Qualifier("restDataSource")
private BasicDataSource restDataSource;
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
return new JwtAccessTokenConverter();
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')").checkTokenAccess(
"hasAuthority('ROLE_TRUSTED_CLIENT')");
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).accessTokenConverter(accessTokenConverter());
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("test")
.authorizedGrantTypes("client_credentials", "password")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write")
.secret("secret");
}
}
}
Those configurations are based on the official spring github repo
The problem I am facing now, is that whenever I try to obtain a token using this url:
http://myapplication.com/test/oauth/token?grant_type=password
I am getting the following error:
java.lang.StackOverflowError
at org.apache.commons.logging.impl.Jdk14Logger.isDebugEnabled(Jdk14Logger.java:214)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:144)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:427)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:177)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:427)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:177)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:427)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:177)
This seems like a loop in the authentication process but to be honest I can find the root of it.
The flow I would like to use is the following:
User asks for a token passing user name, password and client (probably in base64). (METHOD POST)
User is being authenticated.
User is returned a JWT token.
User carries the token in the header.
Can someone advice on the appropriate configurations?
Best
Found the problem, it was specific to the authentication manager.
This is the working configuration for me:
#Configuration
#ComponentScan
#EnableResourceServer
#Import({SecurityConfig.class})
public class OAuth2ServerConfig {
#Configuration
#EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
#Qualifier("restDataSource")
private DataSource datasource;
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
return new JwtAccessTokenConverter();
}
#Bean
public CustomJwtTokenStore tokenStore() {
return new CustomJwtTokenStore();
}
// #Bean
// public JdbcTokenStore tokenStore() {
// return new JdbcTokenStore(datasource);
// }
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')").checkTokenAccess(
"hasAuthority('ROLE_TRUSTED_CLIENT')");
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore()).accessTokenConverter(accessTokenConverter());
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("my-trusted-client")
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust")
.accessTokenValiditySeconds(60)
.and()
.withClient("my-client-with-registered-redirect")
.authorizedGrantTypes("authorization_code")
.authorities("ROLE_CLIENT")
.scopes("read", "trust")
.redirectUris("http://anywhere?key=value")
.and()
.withClient("my-client-with-secret")
.authorizedGrantTypes("client_credentials", "password")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write")
.secret("secret");
}
}
}
with the security config:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationEntryPoint authenticationEntryPoint;
#Autowired
private AccessDeniedHandler accessDeniedHandler;
#Autowired
private GenericFilterBean filter;
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/webjars/**", "/images/**", "/oauth/uncache_approvals", "/oauth/cache_approvals");
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userAuthenticationManager()).passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler) // handle access denied in general (for example comming from #PreAuthorization
.authenticationEntryPoint(authenticationEntryPoint) // handle authentication exceptions for unauthorized calls.
.and()
.authorizeRequests()
.antMatchers("/xxx/**").fullyAuthenticated()
.antMatchers("/xxx/**").fullyAuthenticated()
.antMatchers("/xxx/**").fullyAuthenticated()
.and()
.csrf().disable();;
}
#Bean
#Autowired
ApplicationListener<AbstractAuthenticationEvent> loggerBean() {
return new org.springframework.security.authentication.event.LoggerListener();
}
#Bean
#Autowired
AccessDeniedHandler accessDeniedHandler() {
return new AccessDeniedExceptionHandler();
}
#Bean
#Autowired
AuthenticationEntryPoint entryPointBean() {
return new UnauthorizedEntryPoint();
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean(name="userAuthenticationManager")
public UserDetailsService userAuthenticationManager() throws Exception {
return new UserServiceImpl();
}
#Bean
public UserService userService() {
return new UserServiceImpl();
}
}
Related
For now I have working authentication system, and now trying to add here ldap authentication.
First I should try to signin using my set of users, then if not found, try from ldap server.
But i don't have no idea how to do it.
AuthController:
#RestController
#RequestMapping("/api/v1/auth")
public class AuthController {
#Autowired
AuthenticationManager authenticationManager;
#Autowired
PasswordEncoder encoder;
#Autowired
JwtUtils jwtUtils;
#Autowired
UserService userService;
#PostMapping("/signin")
public ResponseEntity<JwtResponse> authenticateUser(#Valid #RequestBody LoginRequest loginRequest) {
Authentication authentication = authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getUsername(), loginRequest.getPassword()));
SecurityContextHolder.getContext().setAuthentication(authentication);
UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
if (!userDetails.getIsActive()) {
throw new RedoException("Данный пользователь заблокирован");
}
String jwt = jwtUtils.generateJwtToken(authentication);
List<String> permissions = userDetails.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList());
Set<String> groups = userService.getAllGroupsByUser(userDetails.getUsername());
return ResponseEntity.ok(new JwtResponse(jwt,
userDetails.getUsername(),
userDetails.getEmail(),
permissions,
userService.getUserInfoByUsername(userDetails.getUsername()),
groups));
}
}
And WebSecurityConfig:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig {
#Autowired
private AuthEntryPointJwt unauthorizedHandler;
#Autowired
UserDetailsServiceImpl userDetailsService;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("http://localhost:3000"));
configuration.setAllowedOriginPatterns(Collections.singletonList("*")); //set access from all domains
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(Arrays.asList("Authorization", "Cache-Control", "Content-Type"));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
#Configuration
#Order(1)
public class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.antMatcher("/api/v1/external/**")
.authorizeRequests()
.anyRequest().authenticated().and()
.httpBasic();
}
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
}
#Configuration
#Order(2)
public class JwtAuthConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Bean
public AuthTokenFilter authenticationJwtTokenFilter() {
return new AuthTokenFilter();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/api/v1/auth/**", "/api/v1/doc/", "/api/v1/check/", "/swagger-ui/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
#Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
}
}
and i used other project to test only ldap:
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().fullyAuthenticated()
.and()
.formLogin();
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.ldapAuthentication()
.userDnPatterns("uid={0},ou=people")
.groupSearchBase("ou=groups")
.contextSource()
.url("ldap://localhost:8389/dc=springframework,dc=org")
.and()
.passwordCompare()
.passwordEncoder(new BCryptPasswordEncoder())
.passwordAttribute("userPassword");
}
}
some application properties:
spring.ldap.embedded.ldif=classpath:test-server.ldif
spring.ldap.embedded.base-dn=dc=springframework,dc=org
spring.ldap.embedded.port=8389
So how use them both.
I have two microservices, the first for OAuth2 and the second for API. When I log in from the browser, everything works fine, authorization passes and redirection to my API works.
But when I try to do it through Postman(rest), I don’t get access to API.
OAuth2-Server:
Source code for OAuth2 microservice as OAuth2-Server and Resource-Server:
#Configuration
#EnableAuthorizationServer
#EnableResourceServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private BCryptPasswordEncoder passwordEncoder;
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(final AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
#Override
public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("SampleClientId")
.secret(passwordEncoder.encode("secret"))
.authorizedGrantTypes("authorization_code", "password", "client_credentials")
.scopes("user_info")
.autoApprove(true)
.accessTokenValiditySeconds(3600)
;
}
}
#Configuration
#Order(1)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsServiceBean()).passwordEncoder(passwordEncoder());
}
#Override
#Bean(name = "userDetailsService")
public UserDetailsService userDetailsServiceBean()
throws Exception {
return super.userDetailsServiceBean();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception { // #formatter:off
http.requestMatchers()
.antMatchers("/login", "/oauth/authorize")
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.permitAll()
.and().csrf().disable();
} // #formatter:on
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("john")
.password(passwordEncoder().encode("123"))
.roles("USER");
}
#Bean
public BCryptPasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
#RestController
public class UserController {
#RequestMapping("/user/me")
public Principal user(Principal principal) {
System.out.println(principal);
return principal;
}
}
Client-sso:
Source code for Client microservice to use AuthorizationServer for athunticate:
#Configuration
#EnableOAuth2Sso
#EnableWebSecurity
public class UiSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/login**")
.permitAll()
.anyRequest()
.authenticated()
.and()
.logout().permitAll()
.and()
.httpBasic().disable();
}
}
#RestController
public class UserController {
#RequestMapping("/test")
#ResponseBody
public String user() {
return "hiii";
}
}
server:
port: 8082
security:
oauth2:
client:
clientId: SampleClientId
clientSecret: secret
accessTokenUri: http://localhost:8080/oauth/token
userAuthorizationUri: http://localhost:8080/oauth/authorize
resource:
userInfoUri: http://localhost:8080/user/me
I am using spring spring security 5.1.4 and i am trying to authenticate user with custom authentication.
SecurityConfig
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(
securedEnabled = true,
jsr250Enabled = true,
prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
CustomUserDetailsService customUserDetailsService;
#Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
#Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() {
return new JwtAuthenticationFilter();
}
/* #Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder());
}
*/
#Bean(BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Autowired
private CustomAuthenticationProvider authProvider;
#Override
protected void configure(
AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider);
}
#Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js")
.permitAll()
.antMatchers("/api/auth/**")
.permitAll()
.antMatchers("/app/**").permitAll()
.antMatchers("/api/user/checkUsernameAvailability", "/api/user/checkEmailAvailability")
.permitAll()
.antMatchers(HttpMethod.GET, "/api/polls/**", "/api/users/**")
.permitAll()
.anyRequest()
.authenticated();
// Add our custom JWT security filter
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
and my custom authenticationprovider is
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Autowired
private UserRepository userRepository;
#Autowired
private PasswordEncoder passwordEncoder;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
Optional<Tbluser> dbUser = userRepository.findByUsername(authentication.getName());
Tbluser dUser = dbUser.get();
String dbPassword = dUser.getPassword();
boolean passwordsMatch = passwordEncoder.matches(password,dbPassword);
if(!passwordsMatch) {
throw new BadCredentialsException("Invalid username/password");
}
return new UsernamePasswordAuthenticationToken(username, password, Collections.emptyList());
}
#Override
public boolean supports(Class<?>aClass) {
return aClass.equals(UsernamePasswordAuthenticationToken.class);
}
}
so whenever i debug the password i provide in seen in the plain text i.e in authentication object but the password i fetch from database is encoded form.
boolean passwordsMatch = passwordEncoder.matches(password,dbPassword);
is always false.
how do i authenticate them ?
I configure oauth2(resource server and auth server) in my spring boot app, but how to perform authentication now? How to use grants which I described in authentication server?
And how to perform autologin when new user has been registered?
#Configuration
public class OAuth2ServerConfig {
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Inject
private Http401UnauthorizedEntryPoint authenticationEntryPoint;
#Inject
private AjaxLogoutSuccessHandler ajaxLogoutSuccessHandler;
#Override
public void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(authenticationEntryPoint)
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessHandler(ajaxLogoutSuccessHandler)
.and()
.csrf()
.requireCsrfProtectionMatcher(new AntPathRequestMatcher("/authorize"))
.disable()
.headers()
.frameOptions().disable()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/admin").hasAnyAuthority("ADMIN");
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private static final String CLIENTID = "app";
private static final String PROP_SECRET = "secret";
private static final Integer TOKEN_VALIDITY_SECONDS = -1;
#Inject
private OAuth2AccessTokenRepository oAuth2AccessTokenRepository;
#Inject
private OAuth2RefreshTokenRepository oAuth2RefreshTokenRepository;
#Bean
public TokenStore tokenStore() {
return new MongoDBTokenStore(oAuth2AccessTokenRepository, oAuth2RefreshTokenRepository);
}
#Inject
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints
.tokenStore(tokenStore())
.authenticationManager(authenticationManager);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient(CLIENTID)
.scopes("read", "write")
.authorities("USER", "ADMIN")
.authorizedGrantTypes("password", "refresh_token")
.secret(PROP_SECRET)
.accessTokenValiditySeconds(TOKEN_VALIDITY_SECONDS);
}
}
}
You should have something like this:
#Component
public class CustomAuthenticationProvider
implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
if (shouldAuthenticateAgainstThirdPartySystem()) {
// use the credentials
// and authenticate against the third-party system
return new UsernamePasswordAuthenticationToken(
name, password, new ArrayList<>());
} else {
return null;
}
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(
UsernamePasswordAuthenticationToken.class);
}
}
and register it to your SecurityConfig
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private CustomAuthenticationProvider authProvider;
#Override
protected void configure(
AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and()
.httpBasic();
}
}
Working on implementing Oauth2 with Spring. I want to implement the implicit workflow:
My configuration file:
#Configuration
#EnableAutoConfiguration
#RestController
public class App {
#Autowired
private DataSource dataSource;
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
#RequestMapping("/")
public String home() {
return "Hello World";
}
#Configuration
#EnableResourceServer
protected static class ResourceServer extends ResourceServerConfigurerAdapter {
#Autowired
private TokenStore tokenStore;
#Override
public void configure(ResourceServerSecurityConfigurer resources)
throws Exception {
resources.tokenStore(tokenStore);
}
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.authorizeRequests().antMatchers("/oauth/token").authenticated()
.and()
.authorizeRequests().anyRequest().permitAll()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.csrf().disable();
}
}
#Configuration
#EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager auth;
private BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
#Bean
public JdbcTokenStore tokenStore() {
return new JdbcTokenStore(DBConnector.dataSource);
}
#Bean
protected AuthorizationCodeServices authorizationCodeServices() {
return new JdbcAuthorizationCodeServices(DBConnector.dataSource);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security)
throws Exception {
security.passwordEncoder(passwordEncoder);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.authorizationCodeServices(authorizationCodeServices())
.authenticationManager(auth).tokenStore(tokenStore())
.approvalStoreDisabled();
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// #formatter:off
clients.jdbc(DBConnector.dataSource)
.passwordEncoder(passwordEncoder)
.withClient("my-trusted-client")
.secret("test")
.authorizedGrantTypes("password", "authorization_code",
"refresh_token", "implicit")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust")
.resourceIds("oauth2-resource")
.accessTokenValiditySeconds(0);
// #formatter:on
}
}
#Autowired
public void init(AuthenticationManagerBuilder auth) throws Exception {
// #formatter:off
auth.jdbcAuthentication().dataSource(DBConnector.dataSource).withUser("dave")
.password("secret").roles("USER");
// #formatter:on
}
}
This is working so far. A user is also generated in the database.
Problem is following. When i try to do following request:
http://localhost:8080/oauth/token?grant_type=authorization_code&client_id=my-trusted-client&username=dave&password=secret
I always get a popup window (authentication) asking me to enter a username and a password. But it doesn't matter what i enter there i never pass through. So what is wrong there?
I would like to have it, that when i call this url, that i get back my access_token.
In case of implicit flow all token will be generated through authorization url instead of token url. so you should hit ../oauth/authorize endpoint with implicit response type. i.e
../oauth/authorize?response_type=implicit&client_id=trusted_client&redirect_uri=<redirect-uri-of-client-application>.
You are getting the username password popup because token endpoint is already protected through spring's BasicAuthenticationFilter and it is expecting you to pass your client_id as username and client_secret as password. Instead of token endpoint you need to protect authorization endpoint so do your endpoint security configuration as given...
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.authorizeRequests().antMatchers("/oauth/authorize").authenticated()
.and()
.authorizeRequests().anyRequest().permitAll()
.and()
.formLogin().loginPage("/login").permitAll()
.and()
.csrf().disable();
}