package org.apereo.cas.support.oauth.web; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpStatus; import org.apereo.cas.CasProtocolConstants; import org.apereo.cas.authentication.Authentication; import org.apereo.cas.authentication.BasicCredentialMetaData; import org.apereo.cas.authentication.BasicIdentifiableCredential; import org.apereo.cas.authentication.CoreAuthenticationTestUtils; import org.apereo.cas.authentication.CredentialMetaData; import org.apereo.cas.authentication.DefaultAuthenticationBuilder; import org.apereo.cas.authentication.DefaultHandlerResult; import org.apereo.cas.authentication.HandlerResult; import org.apereo.cas.authentication.principal.Principal; import org.apereo.cas.authentication.principal.Service; import org.apereo.cas.authentication.principal.WebApplicationServiceFactory; import org.apereo.cas.mock.MockTicketGrantingTicket; import org.apereo.cas.services.RegisteredService; import org.apereo.cas.services.ReturnAllAttributeReleasePolicy; import org.apereo.cas.services.ServicesManager; import org.apereo.cas.support.oauth.OAuth20Constants; import org.apereo.cas.support.oauth.OAuth20GrantTypes; import org.apereo.cas.support.oauth.services.OAuthRegisteredService; import org.apereo.cas.support.oauth.web.endpoints.OAuth20AccessTokenEndpointController; import org.apereo.cas.ticket.accesstoken.AccessToken; import org.apereo.cas.ticket.code.DefaultOAuthCodeFactory; import org.apereo.cas.ticket.code.OAuthCode; import org.apereo.cas.ticket.code.OAuthCodeFactory; import org.apereo.cas.ticket.refreshtoken.DefaultRefreshTokenFactory; import org.apereo.cas.ticket.refreshtoken.RefreshToken; import org.apereo.cas.ticket.refreshtoken.RefreshTokenFactory; import org.apereo.cas.ticket.support.AlwaysExpiresExpirationPolicy; import org.junit.Before; import org.junit.Test; import org.pac4j.core.context.HttpConstants; import org.pac4j.springframework.web.SecurityInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import java.nio.charset.StandardCharsets; import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import static org.junit.Assert.*; /** * This class tests the {@link OAuth20AccessTokenEndpointController} class. * * @author Jerome Leleu * @since 3.5.2 */ public class OAuth20AccessTokenControllerTests extends AbstractOAuth20Tests { private static final String CONTEXT = "/oauth2.0/"; private static final String CLIENT_ID = "1"; private static final String CLIENT_SECRET = "secret"; private static final String WRONG_CLIENT_SECRET = "wrongSecret"; private static final String REDIRECT_URI = "http://someurl"; private static final String OTHER_REDIRECT_URI = "http://someotherurl"; private static final int TIMEOUT = 7200; private static final String ID = "1234"; private static final String NAME = "attributeName"; private static final String NAME2 = "attributeName2"; private static final String VALUE = "attributeValue"; private static final String USERNAME = "username"; private static final String PASSWORD = "password"; private static final String GOOD_USERNAME = "test"; private static final String GOOD_PASSWORD = "test"; private static final int DELTA = 2; private static final String GET = "GET"; private static final String ERROR_EQUALS = "error="; @Autowired @Qualifier("defaultOAuthCodeFactory") private OAuthCodeFactory oAuthCodeFactory; @Autowired @Qualifier("defaultRefreshTokenFactory") private RefreshTokenFactory oAuthRefreshTokenFactory; @Autowired @Qualifier("accessTokenController") private OAuth20AccessTokenEndpointController oAuth20AccessTokenController; @Autowired @Qualifier("servicesManager") private ServicesManager servicesManager; @Autowired @Qualifier("requiresAuthenticationAccessTokenInterceptor") private SecurityInterceptor requiresAuthenticationInterceptor; @Before public void setUp() { clearAllServices(); } @Test public void verifyClientNoClientId() throws Exception { final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.REDIRECT_URI, REDIRECT_URI); mockRequest.setParameter(OAuth20Constants.CLIENT_SECRET, CLIENT_SECRET); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, OAuth20GrantTypes.AUTHORIZATION_CODE.name().toLowerCase()); final Principal principal = createPrincipal(); final RegisteredService service = addRegisteredService(); final OAuthCode code = addCode(principal, service); mockRequest.setParameter(OAuth20Constants.CODE, code.getId()); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(HttpStatus.SC_UNAUTHORIZED, mockResponse.getStatus()); assertEquals(ERROR_EQUALS + OAuth20Constants.INVALID_REQUEST, mockResponse.getContentAsString()); } @Test public void verifyClientNoRedirectUri() throws Exception { final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.CLIENT_ID, CLIENT_ID); mockRequest.setParameter(OAuth20Constants.CLIENT_SECRET, CLIENT_SECRET); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, OAuth20GrantTypes.AUTHORIZATION_CODE.name().toLowerCase()); final Principal principal = createPrincipal(); final RegisteredService service = addRegisteredService(); final OAuthCode code = addCode(principal, service); mockRequest.setParameter(OAuth20Constants.CODE, code.getId()); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(HttpStatus.SC_BAD_REQUEST, mockResponse.getStatus()); assertEquals(ERROR_EQUALS + OAuth20Constants.INVALID_REQUEST, mockResponse.getContentAsString()); } @Test public void verifyClientNoAuthorizationCode() throws Exception { final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.CLIENT_ID, CLIENT_ID); mockRequest.setParameter(OAuth20Constants.REDIRECT_URI, REDIRECT_URI); mockRequest.setParameter(OAuth20Constants.CLIENT_SECRET, CLIENT_SECRET); final Principal principal = createPrincipal(); final RegisteredService service = addRegisteredService(); final OAuthCode code = addCode(principal, service); mockRequest.setParameter(OAuth20Constants.CODE, code.getId()); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(HttpStatus.SC_BAD_REQUEST, mockResponse.getStatus()); assertEquals(ERROR_EQUALS + OAuth20Constants.INVALID_REQUEST, mockResponse.getContentAsString()); } @Test public void verifyClientBadAuthorizationCode() throws Exception { final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.CLIENT_ID, CLIENT_ID); mockRequest.setParameter(OAuth20Constants.REDIRECT_URI, REDIRECT_URI); mockRequest.setParameter(OAuth20Constants.CLIENT_SECRET, CLIENT_SECRET); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, "badValue"); final Principal principal = createPrincipal(); final RegisteredService service = addRegisteredService(); final OAuthCode code = addCode(principal, service); mockRequest.setParameter(OAuth20Constants.CODE, code.getId()); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(HttpStatus.SC_BAD_REQUEST, mockResponse.getStatus()); assertEquals(ERROR_EQUALS + OAuth20Constants.INVALID_REQUEST, mockResponse.getContentAsString()); } @Test public void verifyClientNoClientSecret() throws Exception { final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.CLIENT_ID, CLIENT_ID); mockRequest.setParameter(OAuth20Constants.REDIRECT_URI, REDIRECT_URI); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, OAuth20GrantTypes.AUTHORIZATION_CODE.name().toLowerCase()); final Principal principal = createPrincipal(); final RegisteredService service = addRegisteredService(); final OAuthCode code = addCode(principal, service); mockRequest.setParameter(OAuth20Constants.CODE, code.getId()); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(HttpStatus.SC_UNAUTHORIZED, mockResponse.getStatus()); assertEquals(ERROR_EQUALS + OAuth20Constants.INVALID_REQUEST, mockResponse.getContentAsString()); } @Test public void verifyClientNoCode() throws Exception { final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.CLIENT_ID, CLIENT_ID); mockRequest.setParameter(OAuth20Constants.REDIRECT_URI, REDIRECT_URI); mockRequest.setParameter(OAuth20Constants.CLIENT_SECRET, CLIENT_SECRET); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, OAuth20GrantTypes.AUTHORIZATION_CODE.name().toLowerCase()); final Principal principal = createPrincipal(); final RegisteredService service = addRegisteredService(); addCode(principal, service); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(HttpStatus.SC_BAD_REQUEST, mockResponse.getStatus()); assertEquals(ERROR_EQUALS + OAuth20Constants.INVALID_REQUEST, mockResponse.getContentAsString()); } @Test public void verifyClientNoCasService() throws Exception { final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.CLIENT_ID, CLIENT_ID); mockRequest.setParameter(OAuth20Constants.REDIRECT_URI, REDIRECT_URI); mockRequest.setParameter(OAuth20Constants.CLIENT_SECRET, CLIENT_SECRET); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, OAuth20GrantTypes.AUTHORIZATION_CODE.name().toLowerCase()); final Principal principal = createPrincipal(); final RegisteredService registeredService = getRegisteredService(REDIRECT_URI, CLIENT_SECRET); final OAuthCode code = addCode(principal, registeredService); mockRequest.setParameter(OAuth20Constants.CODE, code.getId()); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(HttpStatus.SC_UNAUTHORIZED, mockResponse.getStatus()); assertEquals(ERROR_EQUALS + OAuth20Constants.INVALID_REQUEST, mockResponse.getContentAsString()); } @Test public void verifyClientRedirectUriDoesNotStartWithServiceId() throws Exception { final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.CLIENT_ID, CLIENT_ID); mockRequest.setParameter(OAuth20Constants.REDIRECT_URI, OTHER_REDIRECT_URI); mockRequest.setParameter(OAuth20Constants.CLIENT_SECRET, CLIENT_SECRET); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, OAuth20GrantTypes.AUTHORIZATION_CODE.name().toLowerCase()); final Principal principal = createPrincipal(); final RegisteredService service = addRegisteredService(); final OAuthCode code = addCode(principal, service); mockRequest.setParameter(OAuth20Constants.CODE, code.getId()); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(HttpStatus.SC_BAD_REQUEST, mockResponse.getStatus()); assertEquals(ERROR_EQUALS + OAuth20Constants.INVALID_REQUEST, mockResponse.getContentAsString()); } @Test public void verifyClientWrongSecret() throws Exception { final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.CLIENT_ID, CLIENT_ID); mockRequest.setParameter(OAuth20Constants.REDIRECT_URI, REDIRECT_URI); mockRequest.setParameter(OAuth20Constants.CLIENT_SECRET, WRONG_CLIENT_SECRET); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, OAuth20GrantTypes.AUTHORIZATION_CODE.name().toLowerCase()); final Principal principal = createPrincipal(); final RegisteredService service = addRegisteredService(); final OAuthCode code = addCode(principal, service); mockRequest.setParameter(OAuth20Constants.CODE, code.getId()); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(HttpStatus.SC_UNAUTHORIZED, mockResponse.getStatus()); assertEquals(ERROR_EQUALS + OAuth20Constants.INVALID_REQUEST, mockResponse.getContentAsString()); } @Test public void verifyClientExpiredCode() throws Exception { final RegisteredService registeredService = getRegisteredService(REDIRECT_URI, CLIENT_SECRET); servicesManager.save(registeredService); final Map<String, Object> map = new HashMap<>(); map.put(NAME, VALUE); final List<String> list = Arrays.asList(VALUE, VALUE); map.put(NAME2, list); final Principal principal = CoreAuthenticationTestUtils.getPrincipal(ID, map); final Authentication authentication = getAuthentication(principal); final DefaultOAuthCodeFactory expiringOAuthCodeFactory = new DefaultOAuthCodeFactory(new AlwaysExpiresExpirationPolicy()); final WebApplicationServiceFactory factory = new WebApplicationServiceFactory(); final Service service = factory.createService(registeredService.getServiceId()); final OAuthCode code = expiringOAuthCodeFactory.create(service, authentication, new MockTicketGrantingTicket("casuser")); this.ticketRegistry.addTicket(code); final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.CLIENT_ID, CLIENT_ID); mockRequest.setParameter(OAuth20Constants.REDIRECT_URI, REDIRECT_URI); mockRequest.setParameter(OAuth20Constants.CLIENT_SECRET, CLIENT_SECRET); mockRequest.setParameter(OAuth20Constants.CODE, code.getId()); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, OAuth20GrantTypes.AUTHORIZATION_CODE.name().toLowerCase()); servicesManager.save(getRegisteredService(REDIRECT_URI, CLIENT_SECRET)); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(HttpStatus.SC_BAD_REQUEST, mockResponse.getStatus()); assertEquals(ERROR_EQUALS + OAuth20Constants.INVALID_GRANT, mockResponse.getContentAsString()); } @Test public void verifyClientAuthByParameter() throws Exception { final RegisteredService service = addRegisteredService(); internalVerifyClientOK(service, false, false, false); } @Test public void verifyClientAuthByHeader() throws Exception { final RegisteredService service = addRegisteredService(); internalVerifyClientOK(service, true, false, false); } @Test public void verifyClientAuthByParameterWithRefreshToken() throws Exception { final OAuthRegisteredService service = addRegisteredService(); service.setGenerateRefreshToken(true); internalVerifyClientOK(service, false, true, false); } @Test public void verifyClientAuthByHeaderWithRefreshToken() throws Exception { final OAuthRegisteredService service = addRegisteredService(); service.setGenerateRefreshToken(true); internalVerifyClientOK(service, true, true, false); } @Test public void verifyClientAuthJsonByParameter() throws Exception { final OAuthRegisteredService service = addRegisteredService(); service.setJsonFormat(true); internalVerifyClientOK(service, false, false, true); } @Test public void verifyClientAuthJsonByHeader() throws Exception { final OAuthRegisteredService service = addRegisteredService(); service.setJsonFormat(true); internalVerifyClientOK(service, true, false, true); } @Test public void verifyClientAuthJsonByParameterWithRefreshToken() throws Exception { final OAuthRegisteredService service = addRegisteredService(); service.setGenerateRefreshToken(true); service.setJsonFormat(true); internalVerifyClientOK(service, false, true, true); } @Test public void verifyClientAuthJsonByHeaderWithRefreshToken() throws Exception { final OAuthRegisteredService service = addRegisteredService(); service.setGenerateRefreshToken(true); service.setJsonFormat(true); internalVerifyClientOK(service, true, true, true); } private void internalVerifyClientOK(final RegisteredService service, final boolean basicAuth, final boolean refreshToken, final boolean json) throws Exception { final Principal principal = createPrincipal(); final OAuthCode code = addCode(principal, service); final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.REDIRECT_URI, REDIRECT_URI); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, OAuth20GrantTypes.AUTHORIZATION_CODE.name().toLowerCase()); if (basicAuth) { final String auth = CLIENT_ID + ':' + CLIENT_SECRET; final String value = Base64.encodeBase64String(auth.getBytes(StandardCharsets.UTF_8)); mockRequest.addHeader(HttpConstants.AUTHORIZATION_HEADER, HttpConstants.BASIC_HEADER_PREFIX + value); } else { mockRequest.setParameter(OAuth20Constants.CLIENT_ID, CLIENT_ID); mockRequest.setParameter(OAuth20Constants.CLIENT_SECRET, CLIENT_SECRET); } mockRequest.setParameter(OAuth20Constants.CODE, code.getId()); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertNull(this.ticketRegistry.getTicket(code.getId())); assertEquals(HttpStatus.SC_OK, mockResponse.getStatus()); final String body = mockResponse.getContentAsString(); final String accessTokenId; if (json) { assertEquals(MediaType.APPLICATION_JSON_VALUE, mockResponse.getContentType()); assertTrue(body.contains('"' + OAuth20Constants.ACCESS_TOKEN + "\":\"AT-")); if (refreshToken) { assertTrue(body.contains('"' + OAuth20Constants.REFRESH_TOKEN + "\":\"RT-")); } assertTrue(body.contains('"' + OAuth20Constants.EXPIRES_IN + "\":7")); accessTokenId = StringUtils.substringBetween(body, OAuth20Constants.ACCESS_TOKEN + "\":\"", "\",\""); } else { assertEquals(MediaType.TEXT_PLAIN_VALUE, mockResponse.getContentType()); assertTrue(body.contains(OAuth20Constants.ACCESS_TOKEN + "=AT-")); if (refreshToken) { assertTrue(body.contains(OAuth20Constants.REFRESH_TOKEN + "=RT-")); } assertTrue(body.contains(OAuth20Constants.EXPIRES_IN + '=')); accessTokenId = StringUtils.substringBetween(body, OAuth20Constants.ACCESS_TOKEN + '=', "&"); } final AccessToken accessToken = this.ticketRegistry.getTicket(accessTokenId, AccessToken.class); assertEquals(principal, accessToken.getAuthentication().getPrincipal()); final int timeLeft = getTimeLeft(body, refreshToken, json); assertTrue(timeLeft >= TIMEOUT - 10 - DELTA); } private static int getTimeLeft(final String body, final boolean refreshToken, final boolean json) { final int timeLeft; if (json) { if (refreshToken) { timeLeft = Integer.parseInt(StringUtils.substringBetween(body, OAuth20Constants.EXPIRES_IN + "\":", ",")); } else { timeLeft = Integer.parseInt(StringUtils.substringBetween(body, OAuth20Constants.EXPIRES_IN + "\":", "}")); } } else { if (refreshToken) { timeLeft = Integer.parseInt(StringUtils.substringBetween(body, '&' + OAuth20Constants.EXPIRES_IN + '=', '&' + OAuth20Constants.REFRESH_TOKEN)); } else { timeLeft = Integer.parseInt(StringUtils.substringAfter(body, '&' + OAuth20Constants.EXPIRES_IN + '=')); } } return timeLeft; } @Test public void verifyUserNoClientId() throws Exception { addRegisteredService(); final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, OAuth20GrantTypes.PASSWORD.name().toLowerCase()); mockRequest.setParameter(USERNAME, GOOD_USERNAME); mockRequest.setParameter(PASSWORD, GOOD_PASSWORD); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(HttpStatus.SC_UNAUTHORIZED, mockResponse.getStatus()); assertEquals(ERROR_EQUALS + OAuth20Constants.INVALID_REQUEST, mockResponse.getContentAsString()); } @Test public void verifyUserNoCasService() throws Exception { final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.CLIENT_ID, CLIENT_ID); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, OAuth20GrantTypes.PASSWORD.name().toLowerCase()); mockRequest.setParameter(USERNAME, GOOD_USERNAME); mockRequest.setParameter(PASSWORD, GOOD_PASSWORD); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(HttpStatus.SC_UNAUTHORIZED, mockResponse.getStatus()); assertEquals(ERROR_EQUALS + OAuth20Constants.INVALID_REQUEST, mockResponse.getContentAsString()); } @Test public void verifyUserBadAuthorizationCode() throws Exception { addRegisteredService(); final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.CLIENT_ID, CLIENT_ID); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, OAuth20GrantTypes.AUTHORIZATION_CODE.name().toLowerCase()); mockRequest.setParameter(USERNAME, GOOD_USERNAME); mockRequest.setParameter(PASSWORD, GOOD_PASSWORD); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(HttpStatus.SC_BAD_REQUEST, mockResponse.getStatus()); assertEquals(ERROR_EQUALS + OAuth20Constants.INVALID_REQUEST, mockResponse.getContentAsString()); } @Test public void verifyUserBadCredentials() throws Exception { addRegisteredService(); final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.CLIENT_ID, CLIENT_ID); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, OAuth20GrantTypes.PASSWORD.name().toLowerCase()); mockRequest.setParameter(USERNAME, GOOD_USERNAME); mockRequest.setParameter(PASSWORD, "badPassword"); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(HttpStatus.SC_UNAUTHORIZED, mockResponse.getStatus()); assertEquals(ERROR_EQUALS + OAuth20Constants.INVALID_REQUEST, mockResponse.getContentAsString()); } @Test public void verifyUserAuth() throws Exception { addRegisteredService(); internalVerifyUserAuth(false, false); } @Test public void verifyUserAuthWithRefreshToken() throws Exception { final OAuthRegisteredService registeredService = addRegisteredService(); registeredService.setGenerateRefreshToken(true); internalVerifyUserAuth(false, false); } @Test public void verifyJsonUserAuth() throws Exception { final OAuthRegisteredService registeredService = addRegisteredService(); registeredService.setJsonFormat(true); internalVerifyUserAuth(false, true); } @Test public void verifyJsonUserAuthWithRefreshToken() throws Exception { final OAuthRegisteredService registeredService = addRegisteredService(); registeredService.setGenerateRefreshToken(true); registeredService.setJsonFormat(true); internalVerifyUserAuth(false, true); } private void internalVerifyUserAuth(final boolean refreshToken, final boolean json) throws Exception { final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.CLIENT_ID, CLIENT_ID); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, OAuth20GrantTypes.PASSWORD.name().toLowerCase()); mockRequest.setParameter(USERNAME, GOOD_USERNAME); mockRequest.setParameter(PASSWORD, GOOD_PASSWORD); mockRequest.addHeader(CasProtocolConstants.PARAMETER_SERVICE, REDIRECT_URI); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(200, mockResponse.getStatus()); final String body = mockResponse.getContentAsString(); final String accessTokenId; if (json) { assertEquals("application/json", mockResponse.getContentType()); assertTrue(body.contains('"' + OAuth20Constants.ACCESS_TOKEN + "\":\"AT-")); if (refreshToken) { assertTrue(body.contains('"' + OAuth20Constants.REFRESH_TOKEN + "\":\"RT-")); } assertTrue(body.contains('"' + OAuth20Constants.EXPIRES_IN + "\":7")); accessTokenId = StringUtils.substringBetween(body, OAuth20Constants.ACCESS_TOKEN + "\":\"", "\",\""); } else { assertEquals("text/plain", mockResponse.getContentType()); assertTrue(body.contains(OAuth20Constants.ACCESS_TOKEN + '=')); if (refreshToken) { assertTrue(body.contains(OAuth20Constants.REFRESH_TOKEN + '=')); } assertTrue(body.contains(OAuth20Constants.EXPIRES_IN + '=')); accessTokenId = StringUtils.substringBetween(body, OAuth20Constants.ACCESS_TOKEN + '=', "&"); } final AccessToken accessToken = this.ticketRegistry.getTicket(accessTokenId, AccessToken.class); assertEquals(GOOD_USERNAME, accessToken.getAuthentication().getPrincipal().getId()); final int timeLeft = getTimeLeft(body, refreshToken, json); assertTrue(timeLeft >= TIMEOUT - 10 - DELTA); } @Test public void verifyRefreshTokenExpiredToken() throws Exception { final Principal principal = createPrincipal(); final RegisteredService registeredService = addRegisteredService(); final Authentication authentication = getAuthentication(principal); final WebApplicationServiceFactory factory = new WebApplicationServiceFactory(); final Service service = factory.createService(registeredService.getServiceId()); final DefaultRefreshTokenFactory expiringRefreshTokenFactory = new DefaultRefreshTokenFactory(new AlwaysExpiresExpirationPolicy()); final RefreshToken refreshToken = expiringRefreshTokenFactory.create(service, authentication, new MockTicketGrantingTicket("casuser")); this.ticketRegistry.addTicket(refreshToken); final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, OAuth20GrantTypes.REFRESH_TOKEN.name().toLowerCase()); mockRequest.setParameter(OAuth20Constants.CLIENT_ID, CLIENT_ID); mockRequest.setParameter(OAuth20Constants.CLIENT_SECRET, CLIENT_SECRET); mockRequest.setParameter(OAuth20Constants.REFRESH_TOKEN, refreshToken.getId()); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(HttpStatus.SC_BAD_REQUEST, mockResponse.getStatus()); assertEquals(ERROR_EQUALS + OAuth20Constants.INVALID_GRANT, mockResponse.getContentAsString()); } @Test public void verifyRefreshTokenBadCredentials() throws Exception { final Principal principal = createPrincipal(); final RegisteredService service = addRegisteredService(); final RefreshToken refreshToken = addRefreshToken(principal, service); final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, OAuth20GrantTypes.REFRESH_TOKEN.name().toLowerCase()); mockRequest.setParameter(OAuth20Constants.CLIENT_ID, CLIENT_ID); mockRequest.setParameter(OAuth20Constants.CLIENT_SECRET, WRONG_CLIENT_SECRET); mockRequest.setParameter(OAuth20Constants.REFRESH_TOKEN, refreshToken.getId()); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(HttpStatus.SC_UNAUTHORIZED, mockResponse.getStatus()); assertEquals(ERROR_EQUALS + OAuth20Constants.INVALID_REQUEST, mockResponse.getContentAsString()); } @Test public void verifyRefreshTokenMissingToken() throws Exception { addRegisteredService(); final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, OAuth20GrantTypes.REFRESH_TOKEN.name().toLowerCase()); mockRequest.setParameter(OAuth20Constants.CLIENT_ID, CLIENT_ID); mockRequest.setParameter(OAuth20Constants.CLIENT_SECRET, CLIENT_SECRET); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(HttpStatus.SC_BAD_REQUEST, mockResponse.getStatus()); assertEquals(ERROR_EQUALS + OAuth20Constants.INVALID_REQUEST, mockResponse.getContentAsString()); } @Test public void verifyRefreshTokenOK() throws Exception { final OAuthRegisteredService service = addRegisteredService(); internalVerifyRefreshTokenOk(service, false); } @Test public void verifyRefreshTokenOKWithRefreshToken() throws Exception { final OAuthRegisteredService service = addRegisteredService(); service.setGenerateRefreshToken(true); internalVerifyRefreshTokenOk(service, false); } @Test public void verifyJsonRefreshTokenOK() throws Exception { final OAuthRegisteredService service = addRegisteredService(); service.setJsonFormat(true); internalVerifyRefreshTokenOk(service, true); } @Test public void verifyJsonRefreshTokenOKWithRefreshToken() throws Exception { final OAuthRegisteredService service = addRegisteredService(); service.setGenerateRefreshToken(true); service.setJsonFormat(true); internalVerifyRefreshTokenOk(service, true); } private void internalVerifyRefreshTokenOk(final OAuthRegisteredService service, final boolean json) throws Exception { final Principal principal = createPrincipal(); final RefreshToken refreshToken = addRefreshToken(principal, service); final MockHttpServletRequest mockRequest = new MockHttpServletRequest(GET, CONTEXT + OAuth20Constants.ACCESS_TOKEN_URL); mockRequest.setParameter(OAuth20Constants.GRANT_TYPE, OAuth20GrantTypes.REFRESH_TOKEN.name().toLowerCase()); mockRequest.setParameter(OAuth20Constants.CLIENT_ID, CLIENT_ID); mockRequest.setParameter(OAuth20Constants.CLIENT_SECRET, CLIENT_SECRET); mockRequest.setParameter(OAuth20Constants.REFRESH_TOKEN, refreshToken.getId()); final MockHttpServletResponse mockResponse = new MockHttpServletResponse(); requiresAuthenticationInterceptor.preHandle(mockRequest, mockResponse, null); oAuth20AccessTokenController.handleRequest(mockRequest, mockResponse); assertEquals(200, mockResponse.getStatus()); final String body = mockResponse.getContentAsString(); final String accessTokenId; if (json) { assertEquals("application/json", mockResponse.getContentType()); assertTrue(body.contains('"' + OAuth20Constants.ACCESS_TOKEN + "\":\"AT-")); assertFalse(body.contains('"' + OAuth20Constants.REFRESH_TOKEN + "\":\"RT-")); assertTrue(body.contains('"' + OAuth20Constants.EXPIRES_IN + "\":7")); accessTokenId = StringUtils.substringBetween(body, OAuth20Constants.ACCESS_TOKEN + "\":\"", "\",\""); } else { assertEquals("text/plain", mockResponse.getContentType()); assertTrue(body.contains(OAuth20Constants.ACCESS_TOKEN + '=')); assertFalse(body.contains(OAuth20Constants.REFRESH_TOKEN + '=')); assertTrue(body.contains(OAuth20Constants.EXPIRES_IN + '=')); accessTokenId = StringUtils.substringBetween(body, OAuth20Constants.ACCESS_TOKEN + '=', "&"); } final AccessToken accessToken = this.ticketRegistry.getTicket(accessTokenId, AccessToken.class); assertEquals(principal, accessToken.getAuthentication().getPrincipal()); final int timeLeft = getTimeLeft(body, false, json); assertTrue(timeLeft >= TIMEOUT - 10 - DELTA); } private static Principal createPrincipal() { final Map<String, Object> map = new HashMap<>(); map.put(NAME, VALUE); final List<String> list = Arrays.asList(VALUE, VALUE); map.put(NAME2, list); return CoreAuthenticationTestUtils.getPrincipal(ID, map); } private OAuthRegisteredService addRegisteredService() { final OAuthRegisteredService registeredService = getRegisteredService(REDIRECT_URI, CLIENT_SECRET); servicesManager.save(registeredService); return registeredService; } private OAuthCode addCode(final Principal principal, final RegisteredService registeredService) { final Authentication authentication = getAuthentication(principal); final WebApplicationServiceFactory factory = new WebApplicationServiceFactory(); final Service service = factory.createService(registeredService.getServiceId()); final OAuthCode code = oAuthCodeFactory.create(service, authentication, new MockTicketGrantingTicket("casuser")); this.ticketRegistry.addTicket(code); return code; } private RefreshToken addRefreshToken(final Principal principal, final RegisteredService registeredService) { final Authentication authentication = getAuthentication(principal); final WebApplicationServiceFactory factory = new WebApplicationServiceFactory(); final Service service = factory.createService(registeredService.getServiceId()); final RefreshToken refreshToken = oAuthRefreshTokenFactory.create(service, authentication, new MockTicketGrantingTicket("casuser")); this.ticketRegistry.addTicket(refreshToken); return refreshToken; } private static OAuthRegisteredService getRegisteredService(final String serviceId, final String secret) { final OAuthRegisteredService registeredServiceImpl = new OAuthRegisteredService(); registeredServiceImpl.setName("The registered service name"); registeredServiceImpl.setServiceId(serviceId); registeredServiceImpl.setClientId(CLIENT_ID); registeredServiceImpl.setClientSecret(secret); registeredServiceImpl.setAttributeReleasePolicy(new ReturnAllAttributeReleasePolicy()); return registeredServiceImpl; } private void clearAllServices() { final Collection<RegisteredService> col = servicesManager.getAllServices(); col.forEach(r -> servicesManager.delete(r.getId())); servicesManager.load(); } private static Authentication getAuthentication(final Principal principal) { final CredentialMetaData metadata = new BasicCredentialMetaData( new BasicIdentifiableCredential(principal.getId())); final HandlerResult handlerResult = new DefaultHandlerResult(principal.getClass().getCanonicalName(), metadata, principal, new ArrayList<>()); return DefaultAuthenticationBuilder.newInstance() .setPrincipal(principal) .setAuthenticationDate(ZonedDateTime.now()) .addCredential(metadata) .addSuccess(principal.getClass().getCanonicalName(), handlerResult) .build(); } }