Java tutorial
/** * Copyright 2013 Stockholm County Council * * This file is part of APIGW * * APIGW is free software; you can redistribute it and/or modify * it under the terms of version 2.1 of the GNU Lesser General Public * License as published by the Free Software Foundation. * * APIGW is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with APIGW; if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA * */ package org.apigw.authserver; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.util.Arrays; import java.util.EnumSet; import org.apigw.authserver.svc.AdministrationServices; import static org.apigw.authserver.types.domain.CertifiedClientRole.ROLE_CLIENT; import static org.apigw.authserver.types.domain.CertifiedClientRole.ROLE_TRUSTED_CLIENT; import org.apigw.util.OAuthTestHelper; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.Ignore; import org.junit.runner.RunWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.security.oauth2.common.OAuth2AccessToken; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; /** * This class is based on code created by: * @author Dave Syer * @author Luke Taylor * The original code came from the Spring Security Oauth project: * https://github.com/SpringSource/spring-security-oauth * and is licensed under Apache License Version 2.0: * https://github.com/SpringSource/spring-security-oauth/blob/master/license.txt * * The code has been modified and extended by: * @author Albert rwall * @author Christian Hilmersson */ @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:intsvc-integration-test-context.xml") public class AuthorizationCodeProviderIntegrationtest { private static final Logger log = LoggerFactory.getLogger(AuthorizationCodeProviderIntegrationtest.class); private final static String REDIRECT_URL = "http://localhost:8888/apigw-auth-server-web/resources/css/main.css"; private final static String CLIENT_ID = "apitest"; private final static String SCOPE = "CRM_SCHEDULING_READ"; private final static String USERNAME = "196309283221"; private final static String PASSWORD = "koala"; @Rule public ServerRunning serverRunning = ServerRunning.isRunning(); public OAuthTestHelper helper = new OAuthTestHelper(serverRunning, USERNAME, PASSWORD); @Autowired private AdministrationServices administrationServices; private static boolean initialized = false; @Before public void init() { if (AuthorizationCodeProviderIntegrationtest.initialized) { log.info("Already initialized, skipping data population"); return; } log.info("Removing any previously registered data to avoid duplicates..."); if (administrationServices.findCertifiedClientByClientId("another_client") != null) { administrationServices.deleteCertifiedClientByClientId("another_client"); } if (administrationServices.findCertifiedClientByClientId("apitest") != null) { administrationServices.deleteCertifiedClientByClientId("apitest"); } if (administrationServices.findPermission("CLINICALPROCESS_LOGISTICS_LOGISTICS_READ") != null) { administrationServices.deletePermission("CLINICALPROCESS_LOGISTICS_LOGISTICS_READ"); } if (administrationServices.findPermission("CLINICALPROCESS_HEALTHCOND_DESCRIPTION_READ") != null) { administrationServices.deletePermission("CLINICALPROCESS_HEALTHCOND_DESCRIPTION_READ"); } if (administrationServices.findPermission("CRM_CARELISTING_READ") != null) { administrationServices.deletePermission("CRM_CARELISTING_READ"); } if (administrationServices.findPermission("CRM_REQUESTSTATUS_READ") != null) { administrationServices.deletePermission("CRM_REQUESTSTATUS_READ"); } if (administrationServices.findPermission("CRM_SCHEDULING_WRITE") != null) { administrationServices.deletePermission("CRM_SCHEDULING_WRITE"); } if (administrationServices.findPermission("CRM_SCHEDULING_READ") != null) { administrationServices.deletePermission("CRM_SCHEDULING_READ"); } log.info("Populating test data..."); administrationServices.registerPermission("CRM_SCHEDULING_READ", "Lsa tidbokningar"); administrationServices.registerPermission("CRM_SCHEDULING_WRITE", "Skriva tidbokningar"); administrationServices.registerPermission("CRM_REQUESTSTATUS_READ", "Lsa remiss-status"); administrationServices.registerPermission("CRM_CARELISTING_READ", "Lsa listingar"); administrationServices.registerPermission("CLINICALPROCESS_HEALTHCOND_DESCRIPTION_READ", "Lsa vrddokumentation"); administrationServices.registerPermission("CLINICALPROCESS_LOGISTICS_LOGISTICS_READ", "Lsa vrdkontakter"); administrationServices.registerApplication("apitest", "API Test", "Description of the API Test application", 0L, 0L, "CN=Spring Security Test CA,OU=Spring Security,O=Spring Framework,L=Glasgow,ST=Scotland,C=GB", "CN=dianne,OU=Spring Security,O=Spring Framework,C=AU", "Callista Enterprise", Arrays.asList( new String[] { "CRM_SCHEDULING_READ", "CRM_SCHEDULING_WRITE", "CRM_REQUESTSTATUS_READ", "CRM_CARELISTING_READ", "CLINICALPROCESS_HEALTHCOND_DESCRIPTION_READ", "CLINICALPROCESS_LOGISTICS_LOGISTICS_READ" }), "secret", EnumSet.of(ROLE_CLIENT, ROLE_TRUSTED_CLIENT)); administrationServices.registerApplication("another_client", "Another client", "Application description", 0L, 0L, "CA_2", null, "Callista Enterprise", Arrays.asList(new String[] { "CRM_SCHEDULING_READ" }), "secret", EnumSet.of(ROLE_CLIENT, ROLE_TRUSTED_CLIENT)); AuthorizationCodeProviderIntegrationtest.initialized = true; } @Test public void testAuthorizationRequestRedirectsToLogin() throws Exception { log.debug("testAuthorizationRequestRedirectsToLogin"); HttpHeaders headers = new HttpHeaders(); headers.setAccept(Arrays.asList(MediaType.TEXT_HTML)); String location = helper.getAuthorizeUrl(CLIENT_ID, REDIRECT_URL, SCOPE); ResponseEntity<Void> result = serverRunning.getForResponse(location, headers); assertEquals(HttpStatus.FOUND, result.getStatusCode()); location = result.getHeaders().getLocation().toString(); if (result.getHeaders().containsKey("Set-Cookie")) { String cookie = result.getHeaders().getFirst("Set-Cookie"); headers.set("Cookie", cookie); } ResponseEntity<String> response = serverRunning.getForString(location, headers); // should be directed to the login screen... assertTrue(response.getBody().contains("/login.do")); assertTrue(response.getBody().contains("j_username")); assertTrue(response.getBody().contains("j_password")); } @Test public void testSuccessfulAuthorizationCodeFlow() throws Exception { log.debug("testSuccessfulAuthorizationCodeFlow"); String code = helper.getAuthorizationCode(CLIENT_ID, REDIRECT_URL, SCOPE); // Get the token using the authorization code (no session required because it's a back channel) TokenResponseDTO accessToken = helper.getAccessToken(CLIENT_ID, REDIRECT_URL, code, SCOPE); assertNotNull(accessToken); assertNotNull(accessToken.getExpiresIn()); assertFalse(accessToken.getExpiresIn().equals("0")); // first make sure the resource is actually protected. assertFalse(HttpStatus.OK .equals(serverRunning.getStatusCode("/crm-scheduling-api/crm/scheduling/v1/schedule"))); // now make sure an authorized request is valid. HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, accessToken.getAccessToken())); assertEquals(HttpStatus.OK, serverRunning.getStatusCode("/crm-scheduling-api/crm/scheduling/v1/schedule", headers)); } @Test public void testUserDeniesConfirmation() throws Exception { log.debug("testUserDeniesConfirmation"); String cookie = helper.loginAndGetConfirmationPage(CLIENT_ID, REDIRECT_URL, SCOPE); HttpHeaders headers = new HttpHeaders(); headers.setAccept(Arrays.asList(MediaType.TEXT_HTML)); headers.set("Cookie", cookie); MultiValueMap<String, String> formData = new LinkedMultiValueMap<String, String>(); formData.add("user_oauth_approval", "false"); ResponseEntity<Void> result = serverRunning.postForStatus("/apigw-auth-server-web/oauth/authorize", headers, formData); assertEquals(HttpStatus.FOUND, result.getStatusCode()); String location = result.getHeaders().getFirst("Location"); assertTrue(location.startsWith(REDIRECT_URL)); assertTrue(location.substring(location.indexOf('?')).contains("error=access_denied")); assertTrue(location.contains("state=gzzFqB!!!")); } public void testInvalidScopeInTokenRequest() throws Exception { ResponseEntity<Void> response = helper.attemptToGetConfirmationPage(CLIENT_ID, REDIRECT_URL, "bogus"); assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); } @Test public void testNoClientIdProvided() throws Exception { log.debug("testNoClientIdProvided"); ResponseEntity<Void> response = helper.attemptToGetConfirmationPage(null, REDIRECT_URL, SCOPE); assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); } @Test public void testNoRedirect() throws Exception { log.debug("testNoRedirect"); ResponseEntity<Void> response = helper.attemptToGetConfirmationPage(CLIENT_ID, null, SCOPE); assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode()); } @Test public void testInvalidScopeInResourceRequest() throws Exception { log.debug("testInvalidScopeInResourceRequest"); String code = helper.getAuthorizationCode(CLIENT_ID, REDIRECT_URL, "CRM_SCHEDULING_WRITE"); TokenResponseDTO accessToken = helper.getAccessToken(CLIENT_ID, REDIRECT_URL, code, "CRM_SCHEDULING_WRITE", HttpStatus.OK); assertNotNull(accessToken); // now make sure an unauthorized request fails the right way. HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, accessToken.getAccessToken())); ResponseEntity<String> response = serverRunning.getForString("/crm-scheduling-api/crm/scheduling/booking", headers); assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode()); String authenticate = response.getHeaders().getFirst("WWW-Authenticate"); assertNotNull(authenticate); assertTrue(authenticate.startsWith("Bearer")); assertTrue(authenticate.contains("scope=\"")); } @Test public void testInvalidAccessToken() throws Exception { log.debug("testInvalidAccessToken"); // now make sure an unauthorized request fails the right way. HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", String.format("%s %s", OAuth2AccessToken.BEARER_TYPE, "FOO")); ResponseEntity<String> response = serverRunning.getForString("/crm-scheduling-api/crm/scheduling/booking", headers); assertEquals(HttpStatus.UNAUTHORIZED, response.getStatusCode()); String authenticate = response.getHeaders().getFirst("WWW-Authenticate"); assertNotNull(authenticate); assertTrue(authenticate.startsWith("Bearer")); // Resource Server doesn't know what scopes are required until teh token can be validated assertFalse(authenticate.contains("scope=\"")); } }