I want to implement central authentication system with spring security and oauth2 sso. In other words, I have a spring boot application that is responsible for authorization and one simple client. My client has rest API. First I get token from the authorization server, then send a request to client API with an authorization header contains bearer token from above request. But this request always gets me server login page.
Here is the implementation of the server and the client:
Server
AuthorizationServerConfig.java
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("SampleClientId")
.secret("{noop}secret")
.authorizedGrantTypes("password")
.scopes("user_info")
.autoApprove(true);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(this.authenticationManager);
}
ApplicationConfig:
#SpringBootApplication
#EnableResourceServer
public class ApplicationConfig extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(ApplicationConfig.class, args);
}
}
SecurityConfig:
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//this is just example
auth.inMemoryAuthentication().withUser("user").password("{noop}1234").roles("user");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/login", "/oauth/authorize", "/oauth/token")
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().permitAll();
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
application.yml:
server:
port: 8900
servlet:
context-path: /auth
Client:
ApplicationConfig:
#SpringBootApplication
public class ApplicationConfig {
public static void main(String[] args) {
SpringApplication.run(ApplicationConfig.class, args);
}
}
SecurityConfig:
#Configuration
#EnableOAuth2Sso
public class ApplicationSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/", "/login**")
.permitAll()
.anyRequest()
.authenticated();
}
}
TestController:
#RestController
public class HomeController {
#GetMapping("/")
public String index() {
return "home";
}
#RequestMapping("/admin")
public String admin() {
return "admin";
}
}
application.yml:
server:
port: 9000
servlet:
context-path: /client1
security:
basic:
enabled: false
oauth2:
client:
clientId: SampleClientId
clientSecret: secret
accessTokenUri: http://localhost:8900/auth/oauth/token
userAuthorizationUri: http://localhost:8900/auth/oauth/authorize
resource:
userInfoUri: http://localhost:8900/auth/user/me
First, I send client_id and secret code along side with username, password and grant_type to localhost:8900/auth/oauth/token and get a result like this:
{
"access_token": "603b505f-e701-43d0-b8b8-976a2178f7ea",
"token_type": "bearer",
"expires_in": 43199,
"scope": "user_info"
}
Now, I pickup above token and send a request to localhost:9000/client1/admin
with header contains above token. But it seems the client application ignores the header and shows server login page as result. How can I fix this problem?
#EnableOAuth2Sso is an annotation for using OAuth 2.0 as an end-user authentication mechanism (e.g. "A Login with Google" button). This annotation is wiring your app to redirect to a login page on your authorization server where you would log in and then get redirected back to your app.
If this is your intent, then you'll need to update your Authorization Server to support the authorization_code grant flow instead of the password grant flow.
However, if your client is strictly a REST API, then you are more likely to need to wire the client using #EnableResourceServer instead of #EnableOAuth2Sso. A Resource Server is what takes a token as authorization, via the Authorization HTTP header.
Related
I have two clients (client1, client2) and an OAuth (authorization, resource).
I want to logout from one of clients and the other will be logout. I have tried this spring-boot-oauth2-single-sign-off-logout but this only logout my client1 and client2 is still logged in!
Then I try to revoke my tokens while I use this code below:
String username = principal.getName();
Collection<OAuth2AccessToken> accessTokens = tokenStore.findTokensByClientIdAndUserName("client1", username);
accessTokens.forEach(a -> tokenServices.revokeToken(a.getValue()));
This code did not work, even the client1 is still logged in! While I see my redis is empty and there is no token already, but my client1 is still logged in! How that possible?
===========================================================================
Here is my configuration:
Client - application.yml:
server:
port: 8081
servlet:
context-path: /clt1
spring:
application:
name: client1
thymeleaf:
cache: false
security:
oauth2:
client:
client-id: client1
client-secret: secret1
userAuthorizationUri: http://localhost:8000/oa/oauth/authorize
access-token-uri: http://localhost:8000/oa/oauth/token
scope: read, write
#pre-established-redirect-uri: http://localhost:8081/clt1/callback
#registered-redirect-uri: http://localhost:8081/clt1/callback
#use-current-uri: false
resource:
user-info-uri: http://localhost:8000/oa/user
#jwt:
# key-uri: http://localhost:8000/oa/oauth/token_key
logging:
level:
root: info
Client - SecurityConfig:
#Configuration
#EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.antMatcher("/**")
.authorizeRequests()
.antMatchers().permitAll()
.anyRequest().authenticated()
.and()
.logout().logoutSuccessUrl("http://localhost:8000/oa/revokeClient").permitAll();
}
}
Oauth - application.yml:
server:
port: 8000
servlet:
context-path: /oa
spring:
application:
name: security
redis:
host: 127.0.0.1
port: 6379
thymeleaf:
cache: false
logging:
level:
root: info
Oauth - AuthorizationConfig:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private TokenStore tokenStore;
#Autowired
private PasswordEncoder passwordEncoder;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("client1")
.secret(passwordEncoder.encode("secret1"))
.scopes("read", "write")
.redirectUris("http://localhost:8081/clt1/login")
.authorizedGrantTypes("authorization_code", "refresh_token")
.autoApprove(true)
.and()
.withClient("client2")
.secret(passwordEncoder.encode("secret2"))
.scopes("read", "write")
.redirectUris("http://localhost:8082/clt2/login")
.authorizedGrantTypes("authorization_code", "refresh_token")
.autoApprove(true);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore);
}
}
Oauth - ResourceConfig:
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/**")
.authorizeRequests().anyRequest().authenticated();
}
}
Oauth - SecurityConfig:
#Configuration
#EnableWebSecurity
#Order(1)//SecurityConfig >> ResourceConfig
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private PasswordEncoder passwordEncoder;
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.requestMatchers()
.antMatchers("/loginPage", "/login**", "/registerPage", "/register", "/oauth/authorize", "/revokeClient")
.and()
.authorizeRequests()
.antMatchers("/registerPage", "/register").permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin().loginPage("/loginPage").loginProcessingUrl("/login").permitAll();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**", "/docs/**", "/fonts/**", "/img/**", "/js/**", "/plugins/**");
}
}
Oauth - Application:
#SpringBootApplication
#Configuration
public class SsoDemoOauthApplication {
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Autowired
private RedisConnectionFactory connectionFactory;
#Bean
public TokenStore tokenStore() {
return new RedisTokenStore(connectionFactory);
}
public static void main(String[] args) {
SpringApplication.run(SsoDemoOauthApplication.class, args);
}
}
I admit not beeing too clever, but what about putting
.logout().logoutSuccessUrl("http://localhost:8000/oa/logout").permitAll();
instead of
.logout().logoutSuccessUrl("http://localhost:8000/oa/revokeClient").permitAll();
in SecurityConfig of client app? Any drawback?
This question already has an answer here:
Spring Security Authentication issue: HTTP 401
(1 answer)
Closed 4 years ago.
I'm trying to implement SSO using Spring OAuth lib for learning purpose.
The AuthenticationServer looks like this:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory() //
.withClient("acme") //
.secret("acmesecret") //
.authorizedGrantTypes("authorization_code", "refresh_token", "password") //
.scopes("openid");
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
}
WebSecurity like this:
#Configuration
#EnableWebSecurity
public class AuthorizeUrlsSecurityConfig extends WebSecurityConfigurerAdapter {
#Bean(name = BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().loginPage("/login").permitAll().and() //
.logout().and() //
.authorizeRequests().anyRequest().hasRole("USER");
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
}
}
and RestController:
#RestController
#EnableResourceServer
public class UserController {
#GetMapping("/user/me")
public Principal user(Principal principal) {
return principal;
}
}
The web application is kept minimal:
#SpringBootApplication
#EnableOAuth2Sso
public class WebApplication implements WebMvcConfigurer {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
}
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
}
application.yml:
spring:
thymeleaf:
cache: false
security:
basic:
enabled: false
oauth2:
client:
clientId: acme
clientSecret: acmesecret
accessTokenUri: http://localhost:9999/auth/oauth/token
userAuthorizationUri: http://localhost:9999/auth/oauth/authorize
resource:
userInfoUri: http://localhost:9999/auth/user/me
when I enter the URL localhost:8080 I should be redirect to the login (generated by spring?), but I get a 401 error.
2018-09-29 12:42:28.257 DEBUG 7677 --- [nio-9999-exec-2] o.s.s.w.a.ExceptionTranslationFilter : Access is denied (user is anonymous); redirecting to authentication entry point
What am I missing?
Thank you!
You need to set web security configuration in the web application.
The reason why you get 401 is even the login url is not allowed to be connected by Spring Security.
So basically you need to add a java config like the following
#Configuration
#EnableOAuth2Sso
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().permitAll();
}
}
Hope this helps! Happy Coding :)
I'm creating a spring boot 2.0 application and trying to enable oauth2 security. I have Auth server and Resource server in the same application as of now. My client and user details as well as token generated are persisted in databases (mysql) and database schema is the same as provided by spring documentation. When I hit the '/oauth/token/' endpoint providing clientId and clientSecret in header and user's credentials in body using Postman, I'm getting access token successfully.
{
"access_token": "bef2d974-2e7d-4bf0-849d-d80e8021dc50",
"token_type": "bearer",
"refresh_token": "32ed6252-e7ee-442c-b6f9-d83b0511fcff",
"expires_in": 6345,
"scope": "read write trust"
}
But when I try to hit my rest api using this access token, I'm getting 401 Unauthorized error:
{
"timestamp": "2018-08-13T11:17:19.813+0000",
"status": 401,
"error": "Unauthorized",
"message": "Unauthorized",
"path": "/myapp/api/unsecure"
}
The rest APIs I'm hitting are as follows:
http://localhost:8080/myapp/api/unsecure
http://localhost:8080/myapp/api/secure
myapp is the context path of my application.
For 'secure' api, I have provided access token in request header as described in Spring documentation:
Authorization: Bearer bef2d974-2e7d-4bf0-849d-d80e8021dc50
Whereas for unsecure api, I have tried with and without Authentication header. In all cases I'm getting same error for both apis.
Also when I try to print currently authenticated user, its getting printed as anonymousUser.
What I want are as follows:
1) I want my secure api to be accessible only when access token is provided in request header.
2) I want my unsecure api to be accessible by unauthorised user.
3) I should get currently authenticated user using SecurityContextHolder when accessing secure url.
My WebSecurityConfigurerAdapter is as follows:
#Configuration
#EnableWebSecurity(debug=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Autowired
UserDetailsService userDetailsService;
#Autowired
private ClientDetailsService clientDetailsService;
#Bean
public PasswordEncoder userPasswordEncoder() {
return new BCryptPasswordEncoder(8);
}
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws
Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(userPasswordEncoder());
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws
Exception {
return super.authenticationManagerBean();
}
#Bean
#Autowired
public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore
tokenStore){
TokenStoreUserApprovalHandler handler = new
TokenStoreUserApprovalHandler();
handler.setTokenStore(tokenStore);
handler.setRequestFactory(new
DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
return handler;
}
#Bean
#Autowired
public ApprovalStore approvalStore(TokenStore tokenStore) throws
Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.cors().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/index.html", "/**.js", "/**.css", "/").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic();
}
Here using antMatchers I have permitted static pages of Angular 6 application, as I'm planning to use those in my real app. And no, the following line does not work to allow static pages of angular application:
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
My AuthorizationServerConfigurerAdapter is as follows:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends
AuthorizationServerConfigurerAdapter {
#Autowired
private DataSource dataSource;
#Autowired
UserDetailsService userDetailsService;
#Autowired
PasswordEncoder passwordEncoder;
#Autowired
TokenStore tokenStore;
#Autowired
private UserApprovalHandler userApprovalHandler;
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()")
.passwordEncoder(passwordEncoder);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(tokenStore)
.userApprovalHandler(userApprovalHandler)
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
}
My ResourceServerConfigurerAdapter is as follows:
#Configuration
#EnableResourceServer
public abstract class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "resource-server-rest-api";
#Autowired
TokenStore tokenStore;
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources
.resourceId(RESOURCE_ID)
.tokenStore(tokenStore);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.cors().disable()
.anonymous().disable()
.requestMatchers()
.antMatchers("/api/**").and()
.authorizeRequests()
.antMatchers("/api/secure").authenticated()
.antMatchers("/api/unsecure").permitAll();
}
}
But when I enable anonymous access in SecurityConfig and declare my unsecure url as permitAll, then I'm able to access that url.
.antMatchers("/api/unsecure", "/index.html", "/**.js", "/**.css", "/").permitAll()
My Controller class is as follows:
#RestController
#RequestMapping("/api")
public class DemoController {
#GetMapping("/secure")
public void sayHelloFriend() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
System.out.println("Current User: "+authentication.getName());
System.out.println("Hello Friend");
}
#GetMapping("/unsecure")
public void sayHelloStranger() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
System.out.println("Current User: "+authentication.getName());
System.out.println("Hello Stranger");
}
}
Let me know if any more information is needed. Any help will be appreciated. But please keep in mind that its Spring Boot 2.0 not 1.5 as both have some critical differences as per my findings.
Try to added
#Order(SecurityProperties.BASIC_AUTH_ORDER)
for the securityConfig? so the chain will check your Resource server's config first.
And not sure if that your type error, remove the abstract from the resource server.
I have a Spring Boot OAuth2 client & a Spring Boot OAuth 2 ResourceServer that's also an Authorization Service. I know what the problem is. I know OAuth 2 tokens are not allowed via get, only Post. However, I'm at a loss on how to fix it. This seems to come automatically w/ #EnableOAuth2Sso built in. In the code below you can see that class is bare bones. I haven't seen in the WebSecurityConfigurerAdapter mentioning a way to deal w/ this.
I'm not going to include the whole POM but I'm using Spring Boot 1.5.10.RELEASE which includes spring-security-oauth2-2.0.14.RELEASE
I've included my classes & properties files w/ client-id & client-secret XXXed out, Client classes & props first:
Client application.properties:
server.port=7293
server.context-path=/ui
server.session.cookie.name=UISESSION
security.basic.enabled=false
security.oauth2.client.client-id=XXXXX
security.oauth2.client.client-secret=XXXXX
security.oauth2.client.access-token-uri=http://localhost:7291/auth/oauth/token
security.oauth2.client.user-authorization-uri=http://localhost:7291/auth/oauth/token
security.oauth2.resource.user-info-uri=http://localhost:7291/auth/user/me
spring.thymeleaf.cache=false
Client Security Config:
#Configuration
#EnableOAuth2Sso
public class UISecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/**")
.authorizeRequests()
.antMatchers("/", "/login**")
.permitAll()
.anyRequest()
.authenticated();
}
}
Client Spring Boot app class:
#SpringBootApplication
public class OAuth2ClientApplication {
public static void main(String[] args) {
SpringApplication.run(OAuth2ClientApplication.class, args);
}
#Bean
public RequestContextListener requestContextListener(){
return new RequestContextListener();
}
}
Resource/Authentication Server App classes:
application.properties:
server.port=7291
server.context-path=/auth
security.oauth2.client.client-id=XXXXX
security.oauth2.client.client-secret=XXXXX
security.oauth2.authorization.checkTokenAccess=isAuthenticated()
security.oauth2.authorization.token-key-access=permitAll()
security.basic.enabled=false
Auth Server Configuration class:
#Configuration
#EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
private static final Logger logger = LoggerFactory.getLogger(FilteringServiceAuthServerConfig.class);
#Value("${security.oauth2.client.client-id}")
private String clientId;
#Value("${security.oauth2.client.client-secret}")
private String clientSecret;
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient(clientId)
.secret(clientSecret)
.authorizedGrantTypes("authorization_code")
.scopes("user_info")
.autoApprove(true) ;
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
}
and here's my Authorization Server Web Security Config class:
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.requestMatchers()
.antMatchers("/login", "/oauth/authorize", "/oauth/token")
.and()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().permitAll();
// #formatter:on
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.parentAuthenticationManager(authenticationManager)
.inMemoryAuthentication()
.withUser("XXXXX").password("XXXXX").roles("USER", "ADMIN");
}
}
and the Authorization / Resource Server combo Spring Boot Application class:
#SpringBootApplication
#EnableResourceServer
public class FilteringServiceApp extends SpringBootServletInitializer {
private static Logger logger = LoggerFactory.getLogger(FilteringServiceApp.class);
#Value("${matches.file.name}")
private String fileName;
#Autowired
private FilterMatchRepository matchRepo;
#PostConstruct
private void init() {
new MatchInitializer(matchRepo, fileName).init();
}
/**
* Start up the Filter Matching Application
*
* #param args
*/
public static void main(String[] args) {
SpringApplication.run(FilteringServiceApp.class, args);
}
#Bean
public RequestContextListener requestContextListener(){
return new RequestContextListener();
}
}
the error i get when I access the URL this way (after authenticating via client_id & secret_id is:
{
"error": "method_not_allowed",
"error_description": "Request method 'GET' not supported"
}
i used NGrok to see what was happening as I got this error message & you can see that it's clearly accessing /oauth/token via a GET request which is against the spec. here's that output:
HTTP/1.1 302
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Location: http://localhost:7291/auth/oauth/token?client_id=XXXXX&redirect_uri=http://57bfa798.ngrok.io/ui/login&response_type=code&state=BgLGhq
Content-Length: 0
Date: Mon, 26 Feb 2018 09:42:30 GMT
i changed my AuthServerConfig class
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
//... other methods still the same. below fixed the error
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
}
}
I have a system using Spring Boot, Angular 2, Spring OAuth 2 where I have implemented security using #EnableWebSecurity and implemented oauth using #EnableResourceServer and #EnableAuthorizationServer in the same application.
Following are the implemented classes:
SecurityConfig.java
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private ClientDetailsService clientDetailsService;
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("pass").roles("USER").and()
.withUser("username").password("password").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/private/**").hasRole("USER")
.antMatchers("/public/**").permitAll();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
AuthorizationServerConfig.java
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#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","USER")
.scopes("read", "write", "trust")
.secret("secret")
.accessTokenValiditySeconds(1200).
refreshTokenValiditySeconds(6000);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.checkTokenAccess("hasAuthority('USER')");
}
}
ResourceServerConfig.java
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter{
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/public/**").permitAll();
http.authorizeRequests().antMatchers("/private/**").hasRole("USER");
}
}
All the url following the /public are accessible by any users; it's correct. The urls following /private/ are secured by both ResourceServerConfig and SecurityConfig, therefore it's not accessible to anonymous users.
When I request access_token from authorization server using grant_type=password, I get the access_token which I use to access the secured resources by appending the access_token as the parameter. But still the resources are not available and I get the response as below:
localhost:8080/private/user/test/?access_token=92f9d86f-83c4-4896-a203-e21976d4cfa2
{
"timestamp": 1495961323209,
"status": 403,
"error": "Forbidden",
"message": "Access Denied",
"path": "/private/user/test/"
}
But when I remove the antMatchers from SecurityConfig.configure(HttpSecurity), the resources are no longer secured even if the ResourceServerConfig.configure(HttpSecurity) is securing the patters.
My questions:
Is there anything I need to perform in ResourceServerConfig so as to grant access to authorized users from the resource server?
What is difference between #EnableResourceServer and #EnableWebSecurity? Do I need to implement both in this application? (I couldn't find any good answers for this questions)
Your private resource is well secured, but the access_token obtained is not passed the correct way to the server.
You have to pass it as header of the request with
Authorization: Bearer 92f9d86f-83c4-4896-a203-e21976d4cfa2
or as curl command:
curl -H "Authorization: Bearer 92f9d86f-83c4-4896-a203-e21976d4cfa2"