/*
* Copyright 2012-2016 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.oauth2.config.annotation;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.codec.Base64;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.ClientRegistrationException;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* gh-808
*
* @author Joe Grandja
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@WebAppConfiguration
public class Gh808EnableAuthorizationServerTests {
private static final String CLIENT_ID = "acme";
private static final String CLIENT_SECRET = "acmesecret";
private static final String USER_ID = CLIENT_ID;
private static final String USER_SECRET = CLIENT_SECRET + "2";
private static BaseClientDetails client;
private static UserDetails user;
@Autowired
WebApplicationContext context;
@Autowired
FilterChainProxy springSecurityFilterChain;
MockMvc mockMvc;
static {
client = new BaseClientDetails(CLIENT_ID, null, "read,write", "password,client_credentials", "ROLE_ADMIN", "http://example.com/oauth2callback");
client.setClientSecret(CLIENT_SECRET);
user = new User(USER_ID, USER_SECRET, Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")));
}
@Before
public void setup() {
mockMvc = MockMvcBuilders.webAppContextSetup(context).addFilters(springSecurityFilterChain).build();
}
@Test
public void clientAuthenticationFailsUsingUserCredentialsOnClientCredentialsGrantFlow() throws Exception {
mockMvc.perform(post("/oauth/token")
.param("grant_type", "client_credentials")
.header("Authorization", httpBasicCredentials(USER_ID, USER_SECRET)))
.andExpect(status().isUnauthorized());
}
@Test
public void clientAuthenticationFailsUsingUserCredentialsOnResourceOwnerPasswordGrantFlow() throws Exception {
mockMvc.perform(post("/oauth/token")
.param("grant_type", "password")
.param("client_id", CLIENT_ID)
.param("username", USER_ID)
.param("password", USER_SECRET)
.header("Authorization", httpBasicCredentials(USER_ID, USER_SECRET)))
.andExpect(status().isUnauthorized());
}
private String httpBasicCredentials(String userName, String password) {
String headerValue = "Basic ";
byte[] toEncode = null;
try {
toEncode = (userName + ":" + password).getBytes("UTF-8");
} catch (UnsupportedEncodingException e) { }
headerValue += new String(Base64.encode(toEncode));
return headerValue;
}
@Configuration
@EnableAuthorizationServer
@EnableWebMvc
static class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.withClientDetails(clientDetailsService());
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(this.authenticationManager)
.userDetailsService(this.userDetailsService);
}
@Bean
public ClientDetailsService clientDetailsService() {
return new ClientDetailsService() {
@Override
public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException {
return client;
}
};
}
}
@Configuration
@EnableWebSecurity
static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService());
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
// Expose the Global AuthenticationManager
return super.authenticationManagerBean();
}
@Bean
public UserDetailsService userDetailsService() {
return new UserDetailsService() {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return user;
}
};
}
}
}