I am using Spring boot application and I have rest controllers. I just started using OAuth 2.0 in spring to secure my APIs. Here are the configuration classes that I have.
#Configuration
#EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
private static final String HU_REST_RESOURCE_ID = "rest_api";
#Autowired
DataSource dataSource;
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(HU_REST_RESOURCE_ID).stateless(false);
}
#Override
public void configure(HttpSecurity http) throws Exception {
//define URL patterns to enable OAuth2 security
http.
requestMatchers().antMatchers("/user/**").and().
authorizeRequests().antMatchers("/user/**").access("#oauth2.hasScope('read') or (!#oauth2.isOAuth() and hasRole('ROLE_USER'))");
}
}
#Configuration
#EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
DataSource dataSource;
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("my-trusted-client")
.authorizedGrantTypes("password","refresh_token")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust")
.accessTokenValiditySeconds(60)
.refreshTokenValiditySeconds(600)
.and()
.withClient("my-trusted-client-with-secret")
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_USER")
.scopes("read", "write", "trust")
.accessTokenValiditySeconds(60)
.refreshTokenValiditySeconds(600);
}
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource); // access and refresh tokens will be maintain in database
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.allowFormAuthenticationForClients();
}
}
#Configuration
public class GlobalAuthenticationConfig extends GlobalAuthenticationConfigurerAdapter {
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user1").password("user1123").roles("USER");
auth.inMemoryAuthentication().withUser("user2").password("user2123").roles("ADMIN");
}
}
Now, When I hit the URL http://localhost:8080/oauth/token?grant_type=password&client_id=my-trusted-client-with-secret&username=user1&password=user1123 I get the following access tokens and refresh tokens,
{
"access_token": "87379d65-6012-4484-ba6f-e4c61766ede3",
"token_type": "bearer",
"refresh_token": "8b0d0ae3-0855-4465-9d89-a1c31c031b8a",
"expires_in": 59,
"scope": "read write trust"
}
My question is why would anyone pass the credentials as a query parameter? Can we make a post request and send the required parameters in an object as POST request? If yes, how can I do it?
My second question is, here I am using inmemory authentication, i.e two users are hard coded in the code. How can I make it check from the database for user credentials?
When you use https (which you should) the complete query is encrypted before being sent through the network, as explained here:
Are querystring parameters secure in HTTPS (HTTP + SSL)?
Regarding your second question, if you want Spring to check the authorized users from a database, you will have to create a class inheriting from UserDetailsManagerhttp://docs.spring.io/autorepo/docs/spring-security/4.0.3.RELEASE/apidocs/org/springframework/security/provisioning/UserDetailsManager.html
You can then implement its different methods, specially loadUserByUsername(String username) that it implements from UserDetailsService (which is used by the Spring authentication manager), with code which queries your database for the relevant data.
This other question describes how to add that manager to your Spring application How to make a UserDetailsManager available as a bean
Related
I'm trying to implement oauth with token. Everything seems good, but after POST
http://localhost:8080/oauth/token?grant_type=password
with set BasicAuth admin/admin (I have user in database with login admin and password admin)
I got window with basic auth, when i wrote my login and password I got again and again this window with basic auth.
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/**").authenticated();
}
}
.
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()")
.allowFormAuthenticationForClients();
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("android-client")
.authorizedGrantTypes("client-credentials", "password","refresh_token")
.authorities("ROLE_CLIENT", "ROLE_ANDROID_CLIENT")
.scopes("read", "write", "trust")
.resourceIds("oauth2-resource")
.accessTokenValiditySeconds(5000)
.secret("android-secret").refreshTokenValiditySeconds(50000);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager)
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
}
}
.
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserRepository userRepository;
#Bean
public AuthenticationManager customAuthenticationManager() throws Exception {
return authenticationManager();
}
private PasswordEncoder encoder =
PasswordEncoderFactories.createDelegatingPasswordEncoder();
#Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(username -> {
Optional<User> user = userRepository.findById(username);
if (user.isPresent()) {
return new org.springframework.security.core.userdetails.User(user.get().getUsername(), encoder.encode(user.get().getPassword()),
true, true, true, true, AuthorityUtils.createAuthorityList("USER"));
} else {
throw new UsernameNotFoundException("Could not find the user '" + username + "'");
}
});
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().fullyAuthenticated().and().httpBasic().and().csrf().disable();
}
}
VERY IMPORTANT:
if I remove ResourceServerConfig.java I can login via BasicAuth, after wrote admin/admin I got JSON from my localhost:8080 but I wanted access by token.
This is my 1st RESTful API.
Could anyone help me? Does anyone know where I made a mistake?
There is little information on the internet on the internet. How can I fix it ?
You need to send your clientId: "android-client" and the secret "android-secret" as basic authentication credentials instead of your user (admin/admin) credentials which needs to be sent as http parameters (username=admin password = admin) like the "grant_type" parameter
so your request should be like this
http://localhost:8080/oauth/token?grant_type=password&username=admin&password=admin
than add your clientId and secret to the basic authentication credentials
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 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"
I want to use OAuth2 for my REST spring boot project. Using some examples I have created configuration for OAuth2:
#Configuration
public class OAuth2Configuration {
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
.anonymous().disable()
.authorizeRequests().anyRequest().authenticated();
// #formatter:on
}
}
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends
AuthorizationServerConfigurerAdapter {
private TokenStore tokenStore = new InMemoryTokenStore();
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Autowired
private UserDetailsServiceImpl 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", "trust")
.authorities("USER")
.scopes("read", "write")
.resourceIds(RESOURCE_ID)
.secret("clientsecret")
.accessTokenValiditySeconds(1200)
.refreshTokenValiditySeconds(3600);
// #formatter:on
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(this.tokenStore);
return tokenServices;
}
}
}
This is my SecurityConfiguration class:
#Configuration
#EnableWebSecurity
#Order(1)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http
.authorizeRequests().antMatchers("/api/register").permitAll()
.and()
.authorizeRequests().antMatchers("/api/free").permitAll()
.and()
.authorizeRequests().antMatchers("/oauth/token").permitAll()
.and()
.authorizeRequests().antMatchers("/api/secured").hasRole("USER")
.and()
.authorizeRequests().anyRequest().authenticated();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
I tried to check my application with 2 simple requests:
#RequestMapping(value = "/api/secured", method = RequestMethod.GET)
public String checkSecured(){
return "Authorization is ok";
}
#RequestMapping(value = "/api/free", method = RequestMethod.GET)
public String checkFree(){
return "Free from authorization";
}
Firstly I checked two requests:
/api/free returned code 200 and the string "Free from authorization"
/api/secured returned {"timestamp":1487451065106,"status":403,"error":"Forbidden","message":"Access Denied","path":"/api/secured"}
And it seems that they work fine.
Then I got access_token (using credentials from my users database)
/oauth/token?grant_type=password&username=emaila&password=emailo
Response:
{"access_token":"3344669f-c66c-4161-9516-d7e2f31a32e8","token_type":"bearer","refresh_token":"c71c17e4-45ba-458c-9d98-574de33d1859","expires_in":1199,"scope":"read write"}
Then I tried to send a request (with the token I got) for resource which requires authentication:
/api/secured?access_token=3344669f-c66c-4161-9516-d7e2f31a32e8
Here is response:
{"timestamp":1487451630224,"status":403,"error":"Forbidden","message":"Access Denied","path":"/api/secured"}
I cannot understand why access is denied. I am not sure in configurations and it seems that they are incorrect. Also I still do not clearly understand relationships of methods configure(HttpSecurity http) in class which extends WebSecurityConfigurerAdapter and in another which extends ResourceServerConfigurerAdapter.
Thank you for any help!
If you are using spring boot 1.5.1 or recently updated to it, note that they changed the filter order for spring security oauth2 (Spring Boot 1.5 Release Notes).
According to the release notes, try to add the following property to application.properties/yml, after doing that the resource server filters will be used after your other filters as a fallback - this should cause the authorization to be accepted before falling to the resource server:
security.oauth2.resource.filter-order = 3
You can find a good answer for your other questions here: https://stackoverflow.com/questions/28537181
I am trying to implement Spring Security OAuth2 using Java config.
My usecase requires the use of password grant_type.
I have configured this so far without the need for a web.xml and would prefer to keep it that way
Versions I am using:
Spring Framework: 4.1.6
Spring Security: 4.0.1
Spring Security OAuth:2.0.7
To make explaining this easier I have enabled GET on the token endpoint
#Override
public void configure
(AuthorizationServerEndpointsConfigurer endpoints) throws Exception
{
endpoints
.tokenStore(tokenStore)
.authenticationManager(authenticationManager)
.allowedTokenEndpointRequestMethods(HttpMethod.GET); //<-- Enable GET
}
The request that I am making is as follows:
http://localhost:8080/project/oauth/token?
client_id=testClient&
grant_type=password&
username=user&
password=password
The header includes an Authorization header that contains the encoded version of:
Username: user
Password: password
The exception I get is:
HTTP Status 500 - Request processing failed; nested exception is
org.springframework.security.oauth2.provider.NoSuchClientException:
No client with requested id: user
From the exception description it appears that OAuth is looking in the ClientDetailsService for the client: user. However user is a user credential. I am obviously missunderstanding something about the configuration.
My configuration is as follows;
ServletInitializer.java
public class ServletInitializer extends AbstractDispatcherServletInitializer {
#Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.scan(ClassUtils.getPackageName(getClass()));
return context;
}
#Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
#Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
#Override
public void onStartup(ServletContext servletContext) throws ServletException{
super.onStartup(servletContext);
DelegatingFilterProxy filter = new DelegatingFilterProxy("springSecurityFilterChain");
filter.setContextAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher");
servletContext.addFilter("springSecurityFilterChain", filter).addMappingForUrlPatterns(null, false, "/*");
}
}
WebMvcConfig.java
#Configuration
#EnableWebMvc
public class WebMvcConfig extends WebMvcConfigurerAdapter {
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
SecurityConfiguration.java
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception{
auth.
inMemoryAuthentication()
.withUser("user")
.password("password")
.roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception{
http
.authorizeRequests()
.antMatchers("/Services/*")
.authenticated()
.and()
.httpBasic();
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
OAuth2ServerConfig.java
#Configuration
public class OAuth2ServerConfig {
#Configuration
#EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter{
#Autowired
private TokenStore tokenStore;
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception{
clients
.inMemory()
.withClient("testClient")
.secret("secret")
.scopes("read", "write")
.authorities("ROLE_CLIENT")
.authorizedGrantTypes("password", "refresh_token")
.accessTokenValiditySeconds(60)
.refreshTokenValiditySeconds(3600);
}
#Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception{
endpoints
.tokenStore(tokenStore)
.authenticationManager(authenticationManager)
.allowedTokenEndpointRequestMethods(HttpMethod.GET);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
}
}
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources){
resources.resourceId("SomeResourseId").stateless(false);
}
#Override
public void configure(HttpSecurity http) throws Exception{
http
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.authorizeRequests()
.antMatchers("/secure/**").access("#oauth2.hasScope('read')");
}
}
}
Code in gitrepo for ease of access: https://github.com/dooffas/springOauth2
I'm not sure where the 500 comes from in your case. I see a 406 because there is no JSON converter for the access token (Spring used to register one by default for Jackson 1.* but now it only does it for Jackson 2.*). You token endpoint works for me if I add jackson-databind to the classpath, e.g.
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.4.4</version>
<scope>runtime</scope>
</dependency>
This works for me:
$ curl -v testClient:secret#localhost:8080/oauth/token?'grant_type=password&username=user&password=password'
P.S. you really ought not to use GET for a token request.
You have defined different authorities
try this:
#Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception{
auth.
inMemoryAuthentication()
.withUser("user")
.password("password")
.roles("USER", "CLIENT");
}
And add param grant_type=password to your request