diff --git a/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/provider/password/ResourceOwnerPasswordTokenGranter.java b/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/provider/password/ResourceOwnerPasswordTokenGranter.java index c662adbbc..ee45da6f4 100644 --- a/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/provider/password/ResourceOwnerPasswordTokenGranter.java +++ b/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/provider/password/ResourceOwnerPasswordTokenGranter.java @@ -22,7 +22,7 @@ import java.util.Set; import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.InsufficientAuthenticationException; +import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.encoding.PasswordEncoder; import org.springframework.security.authentication.encoding.PlaintextPasswordEncoder; @@ -46,12 +46,17 @@ public class ResourceOwnerPasswordTokenGranter implements TokenGranter { private static final String GRANT_TYPE = "password"; + private final AuthorizationServerTokenServices tokenServices; + private final ClientDetailsService clientDetailsService; + private final AuthenticationManager authenticationManager; + private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder(); - public ResourceOwnerPasswordTokenGranter(AuthenticationManager authenticationManager, AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService) { + public ResourceOwnerPasswordTokenGranter(AuthenticationManager authenticationManager, + AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService) { this.authenticationManager = authenticationManager; this.tokenServices = tokenServices; this.clientDetailsService = clientDetailsService; @@ -63,7 +68,7 @@ public OAuth2AccessToken grant(String grantType, Map parameters, if (!GRANT_TYPE.equals(grantType)) { return null; } - + String username = parameters.get("username"); String password = parameters.get("password"); @@ -73,7 +78,8 @@ public OAuth2AccessToken grant(String grantType, Map parameters, String assertedSecret = clientSecret; if (assertedSecret == null) { throw new UnauthorizedClientException("Client secret is required but not provided."); - } else { + } + else { Object salt = null; if (clientDetails instanceof SaltedClientSecret) { salt = ((SaltedClientSecret) clientDetails).getSalt(); @@ -102,14 +108,20 @@ public OAuth2AccessToken grant(String grantType, Map parameters, && !authorizedGrantTypes.contains(grantType)) { throw new InvalidGrantException("Unauthorized grant type: " + grantType); } - - ClientToken clientAuth = new ClientToken(clientId, new HashSet( - clientDetails.getResourceIds()), clientSecret, authorizationScope, clientDetails.getAuthorities()); + + ClientToken clientAuth = new ClientToken(clientId, new HashSet(clientDetails.getResourceIds()), + clientSecret, authorizationScope, clientDetails.getAuthorities()); Authentication userAuth = new UsernamePasswordAuthenticationToken(username, password); - userAuth = authenticationManager.authenticate(userAuth); - if (userAuth==null || !userAuth.isAuthenticated()) { - throw new InsufficientAuthenticationException("There is no currently logged in user"); + try { + userAuth = authenticationManager.authenticate(userAuth); + } + catch (BadCredentialsException e) { + // If the username/password are wrong the spec says we should send 400/bad grant + throw new InvalidGrantException(e.getMessage()); + } + if (userAuth == null || !userAuth.isAuthenticated()) { + throw new InvalidGrantException("Could not authenticate user: " + username); } return tokenServices.createAccessToken(new OAuth2Authentication(clientAuth, userAuth)); diff --git a/spring-security-oauth2/src/test/java/org/springframework/security/oauth2/provider/password/TestResourceOwnerPasswordTokenGranter.java b/spring-security-oauth2/src/test/java/org/springframework/security/oauth2/provider/password/TestResourceOwnerPasswordTokenGranter.java new file mode 100644 index 000000000..b6d17bbed --- /dev/null +++ b/spring-security-oauth2/src/test/java/org/springframework/security/oauth2/provider/password/TestResourceOwnerPasswordTokenGranter.java @@ -0,0 +1,93 @@ +/* + * Copyright 2006-2011 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.provider.password; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Test; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.oauth2.common.exceptions.InvalidGrantException; +import org.springframework.security.oauth2.common.exceptions.OAuth2Exception; +import org.springframework.security.oauth2.provider.BaseClientDetails; +import org.springframework.security.oauth2.provider.ClientDetails; +import org.springframework.security.oauth2.provider.ClientDetailsService; +import org.springframework.security.oauth2.provider.token.InMemoryTokenStore; +import org.springframework.security.oauth2.provider.token.RandomValueTokenServices; + +/** + * @author Dave Syer + * + */ +public class TestResourceOwnerPasswordTokenGranter { + + protected Authentication validUser = new UsernamePasswordAuthenticationToken("foo", "bar", + Arrays.asList(new SimpleGrantedAuthority("ROLE_USER"))); + + private AuthenticationManager authenticationManager = new AuthenticationManager() { + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + return validUser; + } + }; + + private RandomValueTokenServices providerTokenServices = new RandomValueTokenServices(); + + private ClientDetailsService clientDetailsService = new ClientDetailsService() { + + public ClientDetails loadClientByClientId(String clientId) throws OAuth2Exception { + return new BaseClientDetails("resource", "scope", "password", "ROLE_USER"); + } + }; + + private Map parameters; + + public TestResourceOwnerPasswordTokenGranter() { + providerTokenServices.setTokenStore(new InMemoryTokenStore()); + parameters = new HashMap(); + parameters.put("username", "foo"); + parameters.put("password", "bar"); + } + + @Test + public void testSunnyDay() { + ResourceOwnerPasswordTokenGranter granter = new ResourceOwnerPasswordTokenGranter(authenticationManager, + providerTokenServices, clientDetailsService); + granter.grant("password", parameters, "client", null, Collections.singleton("scope")); + } + + @Test(expected = InvalidGrantException.class) + public void testBadCredentials() { + ResourceOwnerPasswordTokenGranter granter = new ResourceOwnerPasswordTokenGranter(new AuthenticationManager() { + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + throw new BadCredentialsException("test"); + } + }, providerTokenServices, clientDetailsService); + granter.grant("password", parameters, "client", null, Collections.singleton("scope")); + } + + @Test(expected = InvalidGrantException.class) + public void testUnauthenticated() { + validUser = new UsernamePasswordAuthenticationToken("foo", "bar"); + ResourceOwnerPasswordTokenGranter granter = new ResourceOwnerPasswordTokenGranter(authenticationManager, + providerTokenServices, clientDetailsService); + granter.grant("password", parameters, "client", null, Collections.singleton("scope")); + } + +}