I'm trying to create a server with OAuth 2 but I have a problem. I configured OAuth, the user can authorize and get a token but the REST methods are always accesible, for example a user can use method POST when they didn't authorize.
How to configure OAuth so the REST methods run only when a user did authorize?
This is how some of my code looks like (I used this example code):
OAuthConfiguration class
#Configuration
public class OAuth2ServerConfiguration {
private static final String RESOURCE_ID = "restservice";
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends
ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
// #formatter:off
resources
.resourceId(RESOURCE_ID);
// #formatter:on
}
#Override
public void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.authorizeRequests()
.antMatchers("/users").hasRole("ADMIN")
.antMatchers("/greeting").authenticated();
// #formatter:on
}
}
AuthorizationServerConfiguration class:
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private TokenStore tokenStore = new InMemoryTokenStore();
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Autowired
private CustomUserDetailsService userDetailsService;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
// #formatter:off
endpoints
.tokenStore(this.tokenStore)
.authenticationManager(this.authenticationManager)
.userDetailsService(userDetailsService);
// #formatter:on
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// #formatter:off
clients
.inMemory()
.withClient("clientapp")
.authorizedGrantTypes("password", "refresh_token")
.authorities("USER")
.scopes("read", "write")
.resourceIds(RESOURCE_ID)
.secret("123456");
// #formatter:on
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(this.tokenStore);
return tokenServices;
}
}
Rest controller:
#RestController
#RequestMapping("/ABC")
final class Controller {
#Autowired
Repository repository;
#RequestMapping(method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
int create(#RequestBody #Valid Data myData) {
repository.create(myData);
return 1;
}
#RequestMapping(value = "{number}", method = RequestMethod.GET)
Data findByNumber(#PathVariable("number") String number) {
Data data = repository.findByNumber(number);
return data;
}
#RequestMapping(value = "{number}", method = RequestMethod.PUT)
int update(#RequestBody #Valid Data myData) {
int rows = repository.update(myData);
return 1;
}
#RequestMapping(value = "{number}", method = RequestMethod.DELETE)
int delete(#PathVariable("number") String number) {
repository.delete(serialNumber);
return 1;
}
}
You'll want to add .antMatchers("/ABC/**").authenticated()
See jhipster sample oauth2 example
https://github.com/jhipster/jhipster-sample-app-oauth2/blob/master/src/main/java/com/mycompany/myapp/config/OAuth2ServerConfiguration.java
Related
I'm trying to setup a simple Oauth2 Server with Spring Boot with only client_credentials flow for now, using in memory users and clients etc. Basically the most basic project so I can build on it. Haven't used Oauth2 with Spring for some time so I'm a bit stuck. I can get access tokens but it seems Spring does not actually validate the username/password sent by the client. Here are the two config classes (AuthorizationServerConfigurerAdapter, WebSecurityConfigurerAdapter):
#Configuration
#EnableAuthorizationServer
public class OAuthConfiguration extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
private final PasswordEncoder passwordEncoder;
private final UserDetailsService userService;
#Value("${jwt.signing-key}")
private String jwtSigningKey;
#Value("${jwt.accessTokenValidititySeconds}")
private int accessTokenValiditySeconds;
#Value("${jwt.refreshTokenValiditySeconds}")
private int refreshTokenValiditySeconds;
public OAuthConfiguration(AuthenticationManager authenticationManager, PasswordEncoder passwordEncoder, UserDetailsService userService) {
this.authenticationManager = authenticationManager;
this.passwordEncoder = passwordEncoder;
this.userService = userService;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("test-client-id")
.secret(passwordEncoder.encode("test-client-secret"))
.accessTokenValiditySeconds(accessTokenValiditySeconds)
.refreshTokenValiditySeconds(refreshTokenValiditySeconds)
.authorizedGrantTypes("client_credentials")
.scopes("read", "write")
.resourceIds("api");
}
#Override
public void configure(final AuthorizationServerEndpointsConfigurer endpoints) {
endpoints
.accessTokenConverter(accessTokenConverter())
.userDetailsService(userService)
.authenticationManager(authenticationManager);
}
#Bean
JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(jwtSigningKey);
return converter;
}
}
and:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
private final CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
public WebSecurityConfiguration(CustomAuthenticationEntryPoint customAuthenticationEntryPoint) {
this.customAuthenticationEntryPoint = customAuthenticationEntryPoint;
}
#Bean
public DaoAuthenticationProvider authenticationProvider(UserDetailsService userDetailsService) {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder());
provider.setUserDetailsService(userDetailsService);
return provider;
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user1")
.password("$2a$10$sWszOXuTlN0amQi8vXp4cerb.tJUQo.4FzLAnTCsSqChsYhlLdQWW")
.roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().disable().csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and().exceptionHandling().authenticationEntryPoint(customAuthenticationEntryPoint).accessDeniedHandler(new CustomAccessDeniedHandler());
}
}
So I can call the "/oauth/token" endpoint with any username/password I get an access token. However the client ID and client secret are being validated.
Any help is appreciated
It's the default behaviour with grant_type client_credentials. So, you don't need to pass the username and password to the token endpoint with this grant_type. In this flow, AuthorizationServer will only validate the client Id and client secret.
POST /token
Host: authorization-server.com
grant_type=client_credentials
&client_id=xxxxxxxxxx
&client_secret=xxxxxxxxxx
I`m developing a microservice structure using spring-boot, this structure has an external oauth2 Authorization Server and multiples Resource Servers.
My problem is, each http request to my resources, calls a url to my Authorization Server, to validate the token ( .../oauth/check_token/). This way there is a lot of requests. There is a way to validate/check this token only when it is expired?
My Resource servers:
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Value("${security.oauth2.client.client-id}")
private String clientId;
#Value("${security.oauth2.client.client-secret}")
private String clientSecret;
#Value("${security.oauth2.resource.id}")
private String resourceId;
#Value("${security.oauth2.resource.token-info-uri}")
private String tokenInfoUri;
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(ADMIN_ANT_MATCHER).hasRole("ADMIN")
.antMatchers(PROTECTED_ANT_MATCHER).hasRole("USER")
.and()
.csrf().disable();
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenServices(tokenService()).resourceId(resourceId).stateless(true);
}
#Bean
#Primary
public RemoteTokenServices tokenService() {
RemoteTokenServices tokenService = new RemoteTokenServices();
tokenService.setCheckTokenEndpointUrl(tokenInfoUri);
tokenService.setClientId(clientId);
tokenService.setClientSecret(clientSecret);
return tokenService;
}
}
Authorization Server:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Value("${security.oauth2.client.client-id}")
private String clientId;
#Value("${security.oauth2.client.client-secret}")
private String clientSecret;
#Value("${security.oauth2.resource.id}")
private String resourceId;
#Value("${security.oauth2.client.access-token-validity-seconds}")
private Integer tokenValidateSeconds;
#Value("${security.oauth2.client.token-secret}")
private String tokenSecret;
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private TokenStore tokenStore;
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private OauthAccessTokenRepository oauthAccessTokenRepository;
#Autowired
private OauthRefreshTokenRepository oauthRefreshTokenRepository;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(this.tokenStore)
.tokenEnhancer(tokenEnhancer())
.authenticationManager(this.authenticationManager)
.userDetailsService(userDetailsService);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient(clientId)
.authorizedGrantTypes("client_credentials", "password", "refresh_token")
.authorities("ROLE_USER","ROLE_ADMIN")
.scopes("read","write","trust")
.resourceIds(resourceId)
.accessTokenValiditySeconds(tokenValidateSeconds)
.secret(bCryptPasswordEncoder().encode(clientSecret));
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.checkTokenAccess("isAuthenticated()");
}
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(this.tokenStore);
return tokenServices;
}
#Bean
public TokenEnhancer tokenEnhancer() {
return new TokenEnhancer() {
#Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
CustomUser user = (CustomUser) authentication.getPrincipal();
String token = JwtTokenHelper.generateToken(
user.getIdUser(),
user.getTenantID(),
user.getIdEntity(),
user.getIdBusinessUnit(),
user.getProfile(),
tokenValidateSeconds,
tokenSecret
);
((DefaultOAuth2AccessToken) accessToken).setValue(token);
return accessToken;
}
};
}
}
You can remove the need to use the check_token endpoint, by using signed JWT tokens.
When the resource server receive a JWT token, it verify it's signature by using a public key, and the expiration date by checking the corresponding field in the JSON object.
For this you can use the JwtAccessTokenConverter, JwtTokenStore and the nimbus-jose-jwt library.
The downside of this approach is that you cannot revoke a token. It's then preferable to have short lived tokens.
I am using Oauth2 in Spring Boot and I am using JDBC token store to store the JWT tokens. This is my AuthorizationServerConfig
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private static final Logger logger = LoggerFactory.getLogger(AuthorizationServerConfig.class);
static final String MERCHANT_ID = "merchant-id";
static final String MERCHANT_SECRET = "merchant-secret-bcrypted-value";
static final String CUSTOMER_ID = "customer-id";
static final String CUSTOMER_SECRET = "customer-secret-bcrypted-value";
static final String GRANT_TYPE_PASSWORD = "password";
static final String AUTHORIZATION_CODE = "authorization_code";
static final String REFRESH_TOKEN = "refresh_token";
static final String IMPLICIT = "implicit";
static final String SCOPE_READ = "read";
static final String SCOPE_WRITE = "write";
static final String TRUST = "trust";
static final int ACCESS_TOKEN_VALIDITY_SECONDS = 1 * 60 ;
static final int FREFRESH_TOKEN_VALIDITY_SECONDS = 5 * 60 ;
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private DataSource dataSource;
#Resource(name = "UserService")
private UserDetailsService userDetailsService;
#Bean
public JwtAccessTokenConverter accessTokenConverter() throws Exception {
logger.debug("accessTokenConverter");
System.out.println("accessTokenConverter");
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey("asagasdg");
return converter;
}
#Bean
public TokenStore tokenStore() throws Exception {
logger.debug("tokenStore");
return new JdbcTokenStore(dataSource);
}
#Bean
public ApprovalStore approvalStore() throws Exception {
TokenApprovalStore tokenApprovalStore = new TokenApprovalStore();
tokenApprovalStore.setTokenStore(tokenStore());
return tokenApprovalStore;
}
#Override
public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
System.out.println("configure");
configurer
.jdbc(dataSource)
// .inMemory()
.withClient(MERCHANT_ID)
.secret(MERCHANT_SECRET)
.authorizedGrantTypes(GRANT_TYPE_PASSWORD, AUTHORIZATION_CODE, REFRESH_TOKEN, IMPLICIT)
.scopes(SCOPE_READ, SCOPE_WRITE, TRUST)
.accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS).
refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS)
.and()
.withClient(CUSTOMER_ID)
.secret(CUSTOMER_SECRET)
.authorizedGrantTypes(GRANT_TYPE_PASSWORD, AUTHORIZATION_CODE, REFRESH_TOKEN, IMPLICIT)
.scopes(SCOPE_READ, SCOPE_WRITE, TRUST)
.accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS)
.refreshTokenValiditySeconds(FREFRESH_TOKEN_VALIDITY_SECONDS).and()
.build()
;
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
System.out.println("configure below");
endpoints
.pathMapping("/oauth/token","/api/v1/oauth/token")
.tokenStore(tokenStore())
.authenticationManager(authenticationManager)
.accessTokenConverter(accessTokenConverter());
}
#Bean
#Primary
public DefaultTokenServices tokenServices() throws Exception {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
}
So whenever I try to hit this url BASE_URL/api/v1/oauth/token with the userid and secret as Basic-Auth in Postman along with another username, password and grant_type=password I get this error
{
"error": "unauthorized",
"error_description": "Full authentication is required to access this resource"
}
The in-memory was authentication was working fine but when I created the databases oauth_access_token, oauth_refresh_token and oauth_client_details to save and retrieve the JWTs from database, I am getting that error.
This is my ResourceServerConfig
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "resource_id";
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception{
System.out.println("resource server configurer "+resources);
resources.resourceId(RESOURCE_ID).stateless(false);
}
#Override
public void configure(HttpSecurity http) throws Exception {
System.out.println("resource server config");
http
.authorizeRequests()
.antMatchers("api/v1/oauth/token").permitAll()
.antMatchers("/","/css/**","/js/**","/lib/**","/img/**","/scss/**","/templates/**","/device-mockups/**","/vendor/**").permitAll()
.anyRequest().authenticated()
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
And this is my WebSecurityConfigurerAdapter
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Resource(name = "UserService")
private UserDetailsService userDetailsService;
#Autowired
DataSource dataSource;
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
System.out.println("authenticationManagerBean");
return super.authenticationManagerBean();
}
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
System.out.println("globalUserDetails");
auth
.userDetailsService(userDetailsService)
.passwordEncoder(bCryptPasswordEncoder());
}
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() throws Exception {
System.out.println("bcryptEncoder");
return new BCryptPasswordEncoder();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("configure ");
http.cors().and()
.authorizeRequests()
.antMatchers("/","/api/v1/oauth/token","/**").permitAll()
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
;
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
}
I don't know what I am missing. Any help would be highly appreciated. Thanks
Check if you have Headers set in Postman.
Key: Content-Type Value: application/x-www-form-urlencoded
You might have, but you didn't mention. Maybe it helps.
Also, I notice you didn't give permission for all to get a token. Try this in your AuthorizationServerConfigurerAdapter:
#Override
public void configure(
AuthorizationServerSecurityConfigurer oauthServer)
throws Exception {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
ยดยดยด
I have implemented the JWT Application
I am using JWT 0.9.1 version
I am able to generate the Json web token, but when I pass to the http://localhost:8080/api/v1/greeting method I am always getting the same error like 401 Unauthorized.
SpringSecurityConfig.java
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Autowired
private UserDetailsService jwtUserDetailsService;
#Autowired
private JwtRequestFilter jwtRequestFilter;
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
// configure AuthenticationManager so that it knows from where to load
// user for matching credentials
// Use BCryptPasswordEncoder
auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
}
/*#Override
protected void configure(HttpSecurity http) throws Exception{
http.csrf().disable().authorizeRequests().antMatchers("/").permitAll();
}*/
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
// dont authenticate this particular request
.authorizeRequests().antMatchers("/api/v1/authenticate", "/api/v1/register","/api/v1/basicauth")
/*.permitAll().antMatchers(HttpMethod.OPTIONS, "/**")*/
// all other requests need to be authenticated
.permitAll().anyRequest().authenticated().and().
// make sure we use stateless session; session won't be used to
// store user's state.
exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// Add a filter to validate the tokens with every request
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
GreetingController.java
#CrossOrigin(origins = "http://localhost:4200")
#RestController
#RequestMapping("/api/v1")
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
#RequestMapping("/greeting")
public Greeting greeting(#RequestParam(value = "name", defaultValue = "World") String name) {
return new Greeting(counter.incrementAndGet(), String.format(template, name));
}
}
I am getting 401 when I try to access OAuth2 from swagger. It is working fine if Swagger is configured in same project and running on same port. But when I configure swagger in another project with different port then it gives 401.
OAuth2 is accessible and working fine with Postman. I am not able to find why it is giving 401 from different port. I have checked inbound/outbound rules of the running port. Is there any other configuration required for accessing OAuth from different server or port?
OAuth2 project is configured on http://localhost:8090/
SpringBoot project is configured on http://localhost:8888/ from where OAuth2 is giving 401.
WebSecurityConfiguration
#Configuration
#EnableWebSecurity
public class CustomWebSecurityConfig extends WebSecurityConfigurerAdapter {
#Lazy
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.antMatchers("/oauth/**").permitAll()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.csrf().disable();
}
/*
* https://github.com/spring-projects/spring-boot/issues/11136
* Expose it manually (there is bug)
*
* */
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
AuthorizationServerConfig :
#Configuration
#EnableAuthorizationServer
public class CustomAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private static final String CLIENT_ID = "client";
private static final String CLIENT_SECRET = "secret";
private static final String GRANT_TYPE_PASSWORD = "password";
private static final String GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials";
private static final String GRANT_TYPE_REFRESH_TOKEN = "refresh_token";
private static final String GRANT_TYPE_AUTH_CODE = "authorization_code";
private static final String SCOPE_READ = "read";
private static final String SCOPE_WRITE = "write";
private static final String SCOPE_TRUST = "trust";
#Autowired
private AuthenticationManager authenticationManager;
#Autowired
private CustomUserDetailService userDetailsService;
#Autowired
private PasswordEncoder passwordEncoder;
#Value("${config.oauth2.tokenTimeout}")
private int ACCESS_TOKEN_VALIDITY_SECONDS;
#Value("${config.oauth2.tokenTimeout}")
private int REFRESH_TOKEN_VALIDITY_SECONDS;
#Value("${config.oauth2.privateKey}")
private String privateKey;
#Value("${config.oauth2.publicKey}")
private String publicKey;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient(CLIENT_ID)
.authorizedGrantTypes(GRANT_TYPE_CLIENT_CREDENTIALS, GRANT_TYPE_PASSWORD, GRANT_TYPE_REFRESH_TOKEN, GRANT_TYPE_AUTH_CODE)
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes(SCOPE_READ, SCOPE_WRITE, SCOPE_TRUST)
.resourceIds("oauth2-resource")
.accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS)
.refreshTokenValiditySeconds(REFRESH_TOKEN_VALIDITY_SECONDS)
.secret(passwordEncoder.encode(CLIENT_SECRET));
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
.tokenStore(tokenStore())
.userDetailsService(userDetailsService)
.tokenServices(tokenServices())
.accessTokenConverter(accessTokenConverter());
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(privateKey);
return converter;
}
#Bean
public JwtTokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
defaultTokenServices.setTokenEnhancer(accessTokenConverter());
return defaultTokenServices;
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.checkTokenAccess("isAuthenticated()")
.tokenKeyAccess("permitAll()");
}
}
WebSecureConfigurerAdapter:
#Configuration
#EnableResourceServer
public class CustomResourceConfig extends ResourceServerConfigurerAdapter {
#Value("${config.oauth2.publicKey}")
private String publicKey;
#Value("${config.oauth2.privateKey}")
private String privateKey;
#Value("${config.oauth2.resource.id}")
private String resourceId;
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).authenticated()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.antMatchers("/", "/home", "/register", "/login").permitAll()
.antMatchers("/oauth/**").authenticated();
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources
.resourceId(resourceId)
.tokenServices(tokenServices())
.tokenStore(tokenStore());
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
defaultTokenServices.setTokenEnhancer(accessTokenConverter());
return defaultTokenServices;
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(privateKey);
return converter;
}
#Bean
public JwtTokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
}
In Swagger configuration , OAuth security schema should be properly initialized while creating Docket instance. Here Access Token URI is something like : http://localhost:8080/api/oauth/token
#Value("${config.oauth2.accessTokenUri}")
private String accessTokenUri;
#Bean
public Docket productApi() {
return new Docket(DocumentationType.SWAGGER_2)
.select().apis(RequestHandlerSelectors.basePackage("com.authentication")).paths(regex("/.*"))
.paths(PathSelectors.any())
.build()
.securityContexts(Collections.singletonList(securityContext()))
.securitySchemes(Arrays.asList(securitySchema()))
.apiInfo(apiInfo());
}
private OAuth securitySchema() {
List<AuthorizationScope> authorizationScopeList = newArrayList();
authorizationScopeList.add(new AuthorizationScope("read", "read all"));
authorizationScopeList.add(new AuthorizationScope("write", "access all"));
List<GrantType> grantTypes = newArrayList();
GrantType passwordCredentialsGrant = new ResourceOwnerPasswordCredentialsGrant(accessTokenUri);
grantTypes.add(passwordCredentialsGrant);
return new OAuth("oauth2", authorizationScopeList, grantTypes);
}
private SecurityContext securityContext() {
return SecurityContext.builder().securityReferences(defaultAuth())
.build();
}