/**
* Copyright © 2015 Instituto Superior Técnico
*
* This file is part of Bennu OAuth Test.
*
* Bennu OAuth Test is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Bennu OAuth Test 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 Bennu OAuth Test. If not, see <http://www.gnu.org/licenses/>.
*/
package org.fenixedu.bennu.oauth;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.Locale;
import javax.servlet.ServletException;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.fenixedu.bennu.core.domain.User;
import org.fenixedu.bennu.core.domain.UserProfile;
import org.fenixedu.bennu.core.rest.DomainObjectParamConverter;
import org.fenixedu.bennu.core.rest.JsonAwareResource;
import org.fenixedu.bennu.core.rest.JsonBodyReaderWriter;
import org.fenixedu.bennu.core.security.Authenticate;
import org.fenixedu.bennu.oauth.api.ExternalApplicationAuthorizationResources;
import org.fenixedu.bennu.oauth.api.OAuthAuthorizationProvider;
import org.fenixedu.bennu.oauth.api.json.ExternalApplicationAdapter;
import org.fenixedu.bennu.oauth.api.json.ExternalApplicationAuthorizationAdapter;
import org.fenixedu.bennu.oauth.api.json.ExternalApplicationAuthorizationSessionAdapter;
import org.fenixedu.bennu.oauth.api.json.ExternalApplicationScopeAdapter;
import org.fenixedu.bennu.oauth.api.json.ServiceApplicationAdapter;
import org.fenixedu.bennu.oauth.domain.ApplicationUserAuthorization;
import org.fenixedu.bennu.oauth.domain.ApplicationUserSession;
import org.fenixedu.bennu.oauth.domain.ExternalApplication;
import org.fenixedu.bennu.oauth.domain.ExternalApplicationScope;
import org.fenixedu.bennu.oauth.domain.ServiceApplication;
import org.fenixedu.bennu.oauth.jaxrs.BennuOAuthFeature;
import org.fenixedu.bennu.oauth.servlets.OAuthAuthorizationServlet;
import org.fenixedu.commons.i18n.LocalizedString;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import pt.ist.fenixframework.DomainObject;
import pt.ist.fenixframework.FenixFramework;
import pt.ist.fenixframework.test.core.FenixFrameworkRunner;
import com.google.common.base.Joiner;
import com.google.common.io.BaseEncoding;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
@RunWith(FenixFrameworkRunner.class)
public class OAuthServletTest extends JerseyTest {
private static final String GRANT_TYPE_CLIENT_CREDENTIALS = "client_credentials";
private static final String GRANT_TYPE_AUTHORIZATION_CODE = "authorization_code";
private static final String GRANT_TYPE_REFRESH_TOKEN = "refresh_token";
private static final String GRANT_TYPE = "grant_type";
private final static String REDIRECT_URI = "redirect_uri";
private final static String CODE = "code";
private final static String REFRESH_TOKEN = "refresh_token";
private final static String ACCESS_TOKEN = "access_token";
private final static String TOKEN_TYPE = "token_type";
private static volatile ExternalApplication externalApplication;
private static volatile ServiceApplication serviceApplication;
private static volatile OAuthAuthorizationServlet oauthServlet;
private static volatile User user1;
private static volatile ServiceApplication serviceApplicationWithScope;
private static volatile ExternalApplicationScope externalApplicationScope;
private static volatile ExternalApplicationScope serviceApplicationOAuthAccessProvider;
private static volatile ExternalApplicationScope loggedScope;
private static final Locale enGB = Locale.forLanguageTag("en-GB");
@Override
protected void configureClient(ClientConfig config) {
config.register(JsonBodyReaderWriter.class);
}
@Override
protected Application configure() {
return new ResourceConfig(TestResource.class, BennuOAuthFeature.class, ExternalApplicationAuthorizationResources.class,
JsonBodyReaderWriter.class, DomainObjectParamConverter.class, OAuthAuthorizationProvider.class);
}
private static User createUser(String username, String firstName, String lastName, String fullName, String email) {
return new User(username, new UserProfile(firstName, lastName, fullName, email, Locale.getDefault()));
}
public static void initObjects() {
if (user1 == null) {
user1 = createUser("user1", "John", "Doe", "John Doe", "john.doe@fenixedu.org");
}
if (oauthServlet == null) {
oauthServlet = new OAuthAuthorizationServlet();
}
if (serviceApplication == null) {
serviceApplication = new ServiceApplication();
serviceApplication.setAuthor(user1);
serviceApplication.setName("Test Service Application");
serviceApplication.setDescription("This is a test service application");
}
if (serviceApplicationWithScope == null) {
serviceApplicationWithScope = new ServiceApplication();
serviceApplicationWithScope.setAuthorName("John Doe");
serviceApplicationWithScope.setName("Service App with scope");
serviceApplicationWithScope.setDescription("Service App with scope SERVICE");
ExternalApplicationScope scope = new ExternalApplicationScope();
scope.setScopeKey("SERVICE");
scope.setName(new LocalizedString.Builder().with(enGB, "Service Scope").build());
scope.setDescription(new LocalizedString.Builder().with(enGB, "Service scope is for service only").build());
scope.setService(Boolean.TRUE);
serviceApplicationWithScope.addScopes(scope);
}
if (externalApplication == null) {
externalApplication = new ExternalApplication();
externalApplication.setAuthor(user1);
externalApplication.setName("Test External Application");
externalApplication.setDescription("This is a test external application");
externalApplication.setRedirectUrl("http://test.url/callback");
}
if (externalApplicationScope == null) {
externalApplicationScope = new ExternalApplicationScope();
externalApplicationScope.setScopeKey("TEST");
externalApplicationScope.setName(new LocalizedString.Builder().with(enGB, "TEST Scope").build());
externalApplicationScope.setDescription(new LocalizedString.Builder().with(enGB, "TEST scope").build());
externalApplicationScope.setService(Boolean.FALSE);
}
if (serviceApplicationOAuthAccessProvider == null) {
serviceApplicationOAuthAccessProvider = new ExternalApplicationScope();
serviceApplicationOAuthAccessProvider.setScopeKey("OAUTH_AUTHORIZATION_PROVIDER");
serviceApplicationOAuthAccessProvider.setName(new LocalizedString.Builder().with(enGB,
"OAuth Authorization Provider Scope").build());
serviceApplicationOAuthAccessProvider.setDescription(new LocalizedString.Builder().with(enGB,
"OAuth Authorization Provider Scope").build());
}
if (loggedScope == null) {
loggedScope = new ExternalApplicationScope();
loggedScope.setScopeKey("LOGGED");
loggedScope.setName(new LocalizedString.Builder().with(enGB, "Logged Scope").build());
loggedScope.setDescription(new LocalizedString.Builder().with(enGB, "Logged Scope").build());
}
JsonAwareResource.setDefault(ExternalApplication.class, ExternalApplicationAdapter.class);
JsonAwareResource.setDefault(ApplicationUserAuthorization.class, ExternalApplicationAuthorizationAdapter.class);
JsonAwareResource.setDefault(ApplicationUserSession.class, ExternalApplicationAuthorizationSessionAdapter.class);
JsonAwareResource.setDefault(ExternalApplicationScope.class, ExternalApplicationScopeAdapter.class);
JsonAwareResource.setDefault(ServiceApplication.class, ServiceApplicationAdapter.class);
}
@BeforeClass
public static void setup() {
FenixFramework.atomic(OAuthServletTest::initObjects);
}
private String generateToken(DomainObject domainObject) {
String random = "fenix";
String token = Joiner.on(":").join(domainObject.getExternalId(), random);
return Base64.getEncoder().encodeToString(token.getBytes(StandardCharsets.UTF_8)).replace("=", "").replace("+", "-")
.replace("/", "-");
}
@Test
public void testTokenTypeWrongAccessTokenInHeader() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
Authenticate.unmock();
ExternalApplication externalApp = new ExternalApplication();
externalApp.setAuthor(user1);
externalApp.setName("Test External Application");
externalApp.setDescription("This is a test external application");
externalApp.setRedirectUrl("http://test.url/callback");
externalApp.addScopes(externalApplicationScope);
ApplicationUserSession applicationUserSession = new ApplicationUserSession();
applicationUserSession.setCode("fenixedu");
ApplicationUserAuthorization applicationUserAuthorization = new ApplicationUserAuthorization(user1, externalApp);
applicationUserAuthorization.addSession(applicationUserSession);
externalApp.addApplicationUserAuthorization(applicationUserAuthorization);
String clientSecret = externalApp.getExternalId() + ":" + externalApp.getSecret();
req.addHeader(HttpHeaders.AUTHORIZATION,
"Basic " + Base64.getEncoder().encodeToString(clientSecret.getBytes(StandardCharsets.UTF_8)));
req.addParameter(REDIRECT_URI, externalApp.getRedirectUrl());
req.addParameter(CODE, applicationUserSession.getCode());
req.addParameter(GRANT_TYPE, GRANT_TYPE_AUTHORIZATION_CODE);
req.setMethod("POST");
req.setPathInfo("/access_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return status OK", 200, res.getStatus());
String tokenJson = res.getContentAsString();
final JsonObject token = new JsonParser().parse(tokenJson).getAsJsonObject();
Assert.assertTrue("response must be a valid json and have" + ACCESS_TOKEN + " field", token.has(ACCESS_TOKEN)
&& token.get(ACCESS_TOKEN).getAsString().length() > 0);
Assert.assertTrue("response must be a valid json and have " + TOKEN_TYPE + " field", token.has(TOKEN_TYPE)
&& token.get(TOKEN_TYPE).getAsString().length() > 0);
String accessToken = token.get(ACCESS_TOKEN).getAsString() + "fenixedu";
String tokenType = token.get(TOKEN_TYPE).getAsString();
Response result =
target("bennu-oauth").path("test").path("test-scope").request()
.header(HttpHeaders.AUTHORIZATION, tokenType + " " + accessToken).get(Response.class);
Assert.assertEquals("request must fail", 401, result.getStatus());
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void testWrongTokenTypeInHeader() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
Authenticate.unmock();
ExternalApplication externalApp = new ExternalApplication();
externalApp.setAuthor(user1);
externalApp.setName("Test External Application");
externalApp.setDescription("This is a test external application");
externalApp.setRedirectUrl("http://test.url/callback");
externalApp.addScopes(externalApplicationScope);
ApplicationUserSession applicationUserSession = new ApplicationUserSession();
applicationUserSession.setCode("fenixedu");
ApplicationUserAuthorization applicationUserAuthorization = new ApplicationUserAuthorization(user1, externalApp);
applicationUserAuthorization.addSession(applicationUserSession);
externalApp.addApplicationUserAuthorization(applicationUserAuthorization);
String clientSecret = externalApp.getExternalId() + ":" + externalApp.getSecret();
req.addHeader(HttpHeaders.AUTHORIZATION,
"Basic " + Base64.getEncoder().encodeToString(clientSecret.getBytes(StandardCharsets.UTF_8)));
req.addParameter(REDIRECT_URI, externalApp.getRedirectUrl());
req.addParameter(CODE, applicationUserSession.getCode());
req.addParameter(GRANT_TYPE, GRANT_TYPE_AUTHORIZATION_CODE);
req.setMethod("POST");
req.setPathInfo("/access_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return status OK", 200, res.getStatus());
String tokenJson = res.getContentAsString();
final JsonObject token = new JsonParser().parse(tokenJson).getAsJsonObject();
Assert.assertTrue("response must be a valid json and have" + ACCESS_TOKEN + " field", token.has(ACCESS_TOKEN)
&& token.get(ACCESS_TOKEN).getAsString().length() > 0);
Assert.assertTrue("response must be a valid json and have " + TOKEN_TYPE + " field", token.has(TOKEN_TYPE)
&& token.get(TOKEN_TYPE).getAsString().length() > 0);
String accessToken = token.get(ACCESS_TOKEN).getAsString();
String tokenType = token.get(TOKEN_TYPE).getAsString() + "fenixedu";
Response result =
target("bennu-oauth").path("test").path("test-scope").request()
.header(HttpHeaders.AUTHORIZATION, tokenType + " " + accessToken).get(Response.class);
Assert.assertEquals("request must fail", 401, result.getStatus());
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void testTokenTypeRefreshAccessTokenInHeader() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
Authenticate.unmock();
ExternalApplication externalApp = new ExternalApplication();
externalApp.setAuthor(user1);
externalApp.setName("Test External Application");
externalApp.setDescription("This is a test external application");
externalApp.setRedirectUrl("http://test.url/callback");
externalApp.addScopes(externalApplicationScope);
ApplicationUserSession applicationUserSession = new ApplicationUserSession();
applicationUserSession.setTokens(generateToken(applicationUserSession), generateToken(applicationUserSession));
ApplicationUserAuthorization applicationUserAuthorization = new ApplicationUserAuthorization(user1, externalApp);
applicationUserAuthorization.addSession(applicationUserSession);
externalApp.addApplicationUserAuthorization(applicationUserAuthorization);
String clientSecret = externalApp.getExternalId() + ":" + externalApp.getSecret();
req.addHeader(HttpHeaders.AUTHORIZATION,
"Basic " + Base64.getEncoder().encodeToString(clientSecret.getBytes(StandardCharsets.UTF_8)));
req.addParameter(REFRESH_TOKEN, applicationUserSession.getRefreshToken());
req.addParameter(GRANT_TYPE, GRANT_TYPE_REFRESH_TOKEN);
req.setMethod("POST");
req.setPathInfo("/refresh_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return status OK", 200, res.getStatus());
String tokenJson = res.getContentAsString();
final JsonObject token = new JsonParser().parse(tokenJson).getAsJsonObject();
Assert.assertTrue("response must be a valid json and have access_token field",
token.has(ACCESS_TOKEN) && token.get(ACCESS_TOKEN).getAsString().length() > 0);
Assert.assertTrue("response must be a valid json and have " + TOKEN_TYPE + " field", token.has(TOKEN_TYPE)
&& token.get(TOKEN_TYPE).getAsString().length() > 0);
String accessToken = token.get(ACCESS_TOKEN).getAsString();
String tokenType = token.get(TOKEN_TYPE).getAsString();
String result =
target("bennu-oauth").path("test").path("test-scope").request()
.header(HttpHeaders.AUTHORIZATION, tokenType + " " + accessToken).get(String.class);
Assert.assertEquals("this is an endpoint with TEST scope user1", result);
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void testTokenTypeInHeader() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
Authenticate.unmock();
ExternalApplication externalApp = new ExternalApplication();
externalApp.setAuthor(user1);
externalApp.setName("Test External Application");
externalApp.setDescription("This is a test external application");
externalApp.setRedirectUrl("http://test.url/callback");
externalApp.addScopes(externalApplicationScope);
ApplicationUserSession applicationUserSession = new ApplicationUserSession();
applicationUserSession.setCode("fenixedu");
ApplicationUserAuthorization applicationUserAuthorization = new ApplicationUserAuthorization(user1, externalApp);
applicationUserAuthorization.addSession(applicationUserSession);
externalApp.addApplicationUserAuthorization(applicationUserAuthorization);
String clientSecret = externalApp.getExternalId() + ":" + externalApp.getSecret();
req.addHeader(HttpHeaders.AUTHORIZATION,
"Basic " + Base64.getEncoder().encodeToString(clientSecret.getBytes(StandardCharsets.UTF_8)));
req.addParameter(REDIRECT_URI, externalApp.getRedirectUrl());
req.addParameter(CODE, applicationUserSession.getCode());
req.addParameter(GRANT_TYPE, GRANT_TYPE_AUTHORIZATION_CODE);
req.setMethod("POST");
req.setPathInfo("/access_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return status OK", 200, res.getStatus());
String tokenJson = res.getContentAsString();
final JsonObject token = new JsonParser().parse(tokenJson).getAsJsonObject();
Assert.assertTrue("response must be a valid json and have" + ACCESS_TOKEN + " field", token.has(ACCESS_TOKEN)
&& token.get(ACCESS_TOKEN).getAsString().length() > 0);
Assert.assertTrue("response must be a valid json and have " + TOKEN_TYPE + " field", token.has(TOKEN_TYPE)
&& token.get(TOKEN_TYPE).getAsString().length() > 0);
String accessToken = token.get(ACCESS_TOKEN).getAsString();
String tokenType = token.get(TOKEN_TYPE).getAsString();
String result =
target("bennu-oauth").path("test").path("test-scope").request()
.header(HttpHeaders.AUTHORIZATION, tokenType + " " + accessToken).get(String.class);
Assert.assertEquals("this is an endpoint with TEST scope user1", result);
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void getAccessTokenHeaderTest() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
Authenticate.unmock();
ExternalApplication externalApp = new ExternalApplication();
externalApp.setAuthor(user1);
externalApp.setName("Test External Application");
externalApp.setDescription("This is a test external application");
externalApp.setRedirectUrl("http://test.url/callback");
ApplicationUserSession applicationUserSession = new ApplicationUserSession();
applicationUserSession.setCode("fenixedu");
ApplicationUserAuthorization applicationUserAuthorization = new ApplicationUserAuthorization(user1, externalApp);
applicationUserAuthorization.addSession(applicationUserSession);
externalApp.addApplicationUserAuthorization(applicationUserAuthorization);
String clientSecret = externalApp.getExternalId() + ":" + externalApp.getSecret();
req.addHeader(HttpHeaders.AUTHORIZATION,
"Basic " + Base64.getEncoder().encodeToString(clientSecret.getBytes(StandardCharsets.UTF_8)));
req.addParameter(REDIRECT_URI, externalApp.getRedirectUrl());
req.addParameter(CODE, applicationUserSession.getCode());
req.addParameter(GRANT_TYPE, GRANT_TYPE_AUTHORIZATION_CODE);
req.setMethod("POST");
req.setPathInfo("/access_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return status OK", 200, res.getStatus());
String tokenJson = res.getContentAsString();
final JsonObject token = new JsonParser().parse(tokenJson).getAsJsonObject();
Assert.assertTrue("response must be a valid json and have access_token field",
token.has(ACCESS_TOKEN) && token.get(ACCESS_TOKEN).getAsString().length() > 0);
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void getAccessTokenWrongClientIdHeaderTest() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
Authenticate.unmock();
ExternalApplication externalApp = new ExternalApplication();
externalApp.setAuthor(user1);
externalApp.setName("Test External Application");
externalApp.setDescription("This is a test external application");
externalApp.setRedirectUrl("http://test.url/callback");
ApplicationUserSession applicationUserSession = new ApplicationUserSession();
applicationUserSession.setCode("fenixedu");
ApplicationUserAuthorization applicationUserAuthorization = new ApplicationUserAuthorization(user1, externalApp);
applicationUserAuthorization.addSession(applicationUserSession);
externalApp.addApplicationUserAuthorization(applicationUserAuthorization);
String clientSecret = "fenixedu:fenixedu";
req.addHeader(HttpHeaders.AUTHORIZATION,
"Basic " + Base64.getEncoder().encodeToString(clientSecret.getBytes(StandardCharsets.UTF_8)));
req.addParameter(REDIRECT_URI, externalApp.getRedirectUrl());
req.addParameter(CODE, applicationUserSession.getCode());
req.addParameter(GRANT_TYPE, GRANT_TYPE_AUTHORIZATION_CODE);
req.setMethod("POST");
req.setPathInfo("/access_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return status BAD_REQUEST", 400, res.getStatus());
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void refreshAccessTokenHeaderTest() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
Authenticate.unmock();
ExternalApplication externalApp = new ExternalApplication();
externalApp.setAuthor(user1);
externalApp.setName("Test External Application");
externalApp.setDescription("This is a test external application");
externalApp.setRedirectUrl("http://test.url/callback");
ApplicationUserSession applicationUserSession = new ApplicationUserSession();
applicationUserSession.setTokens(generateToken(applicationUserSession), generateToken(applicationUserSession));
ApplicationUserAuthorization applicationUserAuthorization = new ApplicationUserAuthorization(user1, externalApp);
applicationUserAuthorization.addSession(applicationUserSession);
externalApp.addApplicationUserAuthorization(applicationUserAuthorization);
String clientSecret = externalApp.getExternalId() + ":" + externalApp.getSecret();
req.addHeader(HttpHeaders.AUTHORIZATION,
"Basic " + Base64.getEncoder().encodeToString(clientSecret.getBytes(StandardCharsets.UTF_8)));
req.addParameter(REFRESH_TOKEN, applicationUserSession.getRefreshToken());
req.addParameter(GRANT_TYPE, GRANT_TYPE_REFRESH_TOKEN);
req.setMethod("POST");
req.setPathInfo("/refresh_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return status OK", 200, res.getStatus());
String tokenJson = res.getContentAsString();
final JsonObject token = new JsonParser().parse(tokenJson).getAsJsonObject();
Assert.assertTrue("response must be a valid json and have access_token field",
token.has(ACCESS_TOKEN) && token.get(ACCESS_TOKEN).getAsString().length() > 0);
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void refreshAccessTokenWrongClientHeaderRefreshTest() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
Authenticate.unmock();
ExternalApplication externalApp = new ExternalApplication();
externalApp.setAuthor(user1);
externalApp.setName("Test External Application");
externalApp.setDescription("This is a test external application");
externalApp.setRedirectUrl("http://test.url/callback");
ApplicationUserSession applicationUserSession = new ApplicationUserSession();
applicationUserSession.setTokens(generateToken(applicationUserSession), generateToken(applicationUserSession));
ApplicationUserAuthorization applicationUserAuthorization = new ApplicationUserAuthorization(user1, externalApp);
applicationUserAuthorization.addSession(applicationUserSession);
externalApp.addApplicationUserAuthorization(applicationUserAuthorization);
String clientSecret = "fenixedu:fenixedu";
req.addHeader(HttpHeaders.AUTHORIZATION,
"Basic " + Base64.getEncoder().encodeToString(clientSecret.getBytes(StandardCharsets.UTF_8)));
req.addParameter(REFRESH_TOKEN, applicationUserSession.getRefreshToken());
req.addParameter(GRANT_TYPE, GRANT_TYPE_REFRESH_TOKEN);
req.setMethod("POST");
req.setPathInfo("/refresh_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return status BAD_REQUEST", 400, res.getStatus());
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void getServiceAccessTokenHeaderEmptyTest() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
Authenticate.unmock();
String clientSecret = "";
req.addHeader(HttpHeaders.AUTHORIZATION,
"Basic " + Base64.getEncoder().encodeToString(clientSecret.getBytes(StandardCharsets.UTF_8)));
req.addParameter(GRANT_TYPE, GRANT_TYPE_CLIENT_CREDENTIALS);
req.setMethod("POST");
req.setPathInfo("/access_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return BAD_REQUEST", 400, res.getStatus());
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void getServiceAccessTokenHeaderTest() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
Authenticate.unmock();
String clientSecret = serviceApplication.getExternalId() + ":" + serviceApplication.getSecret();
req.addHeader(HttpHeaders.AUTHORIZATION,
"Basic " + Base64.getEncoder().encodeToString(clientSecret.getBytes(StandardCharsets.UTF_8)));
req.addParameter(GRANT_TYPE, GRANT_TYPE_CLIENT_CREDENTIALS);
req.setMethod("POST");
req.setPathInfo("/access_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return status OK", 200, res.getStatus());
String tokenJson = res.getContentAsString();
final JsonObject token = new JsonParser().parse(tokenJson).getAsJsonObject();
Assert.assertTrue("response must be a valid json and have access_token field",
token.has(ACCESS_TOKEN) && token.get(ACCESS_TOKEN).getAsString().length() > 0);
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void getServiceAccessTokenTest() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
req.addParameter("client_id", serviceApplication.getExternalId());
req.addParameter("client_secret", serviceApplication.getSecret());
req.addParameter("grant_type", "client_credentials");
req.setMethod("POST");
req.setPathInfo("/access_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return status OK", 200, res.getStatus());
String tokenJson = res.getContentAsString();
final JsonObject token = new JsonParser().parse(tokenJson).getAsJsonObject();
Assert.assertTrue("response must be a valid json and have access_token field",
token.has(ACCESS_TOKEN) && token.get(ACCESS_TOKEN).getAsString().length() > 0);
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void testNormalEndpoint() {
String res = target("bennu-oauth").path("test").path("normal").request().get(String.class);
Assert.assertEquals("message must be the same", "this is a normal endpoint", res);
}
@Test
public void testOAuthEndpointWithoutToken() {
Authenticate.unmock();
try {
target("bennu-oauth").path("test-scope").request().get();
} catch (WebApplicationException e) {
Assert.assertNotEquals("invocation of oauth endpoint without tokens must fail", Status.OK.getStatusCode(), e
.getResponse().getStatus());
}
}
@Test
public void testOAuthEndpointWithTokenWithDifferentScope() {
Authenticate.unmock();
User user = createUser("testOAuthEndpointWithToken", "John", "Doe", "John Doe", "john.doe@fenixedu.org");
ExternalApplication externalApp = new ExternalApplication();
externalApp.setAuthor(user);
externalApp.setName("Test External Application");
externalApp.setDescription("This is a test external application");
externalApp.setRedirectUrl("http://test.url/callback");
ExternalApplicationScope testScope = new ExternalApplicationScope();
testScope.setScopeKey("TEST2");
testScope.setName(new LocalizedString.Builder().with(enGB, "Test Scope").build());
testScope.setDescription(new LocalizedString.Builder().with(enGB, "Test Scope").build());
externalApp.addScopes(testScope);
ApplicationUserSession applicationUserSession = new ApplicationUserSession();
String accessToken = generateToken(applicationUserSession);
ApplicationUserAuthorization applicationUserAuthorization = new ApplicationUserAuthorization(user, externalApp);
externalApp.addApplicationUserAuthorization(applicationUserAuthorization);
applicationUserSession.setTokens(accessToken, null);
applicationUserAuthorization.addSession(applicationUserSession);
try {
target("bennu-oauth").path("test-scope").queryParam("access_token", accessToken).request().get(String.class);
} catch (WebApplicationException e) {
Assert.assertNotEquals("invocation of oauth endpoint with wrong scope must fail", Status.OK.getStatusCode(), e
.getResponse().getStatus());
} finally {
testScope.setBennu(null);
}
}
@Test
public void testServiceOnlyEndpoint() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
req.addParameter("client_id", serviceApplication.getExternalId());
req.addParameter("client_secret", serviceApplication.getSecret());
req.addParameter("grant_type", "client_credentials");
req.setMethod("POST");
req.setPathInfo("/access_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return status OK", 200, res.getStatus());
String tokenJson = res.getContentAsString();
final JsonObject token = new JsonParser().parse(tokenJson).getAsJsonObject();
final String accessToken = token.get(ACCESS_TOKEN).getAsString();
Assert.assertTrue("response must be a valid json and have access_token field",
token.has(ACCESS_TOKEN) && accessToken.length() > 0);
String result =
target("bennu-oauth").path("test").path("service-only-without-scope").queryParam(ACCESS_TOKEN, accessToken)
.request().get(String.class);
Assert.assertEquals("this is an endpoint with serviceOnly", result);
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void testServiceOnlyEndpointWithScopeMustFail() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
req.addParameter("client_id", serviceApplication.getExternalId());
req.addParameter("client_secret", serviceApplication.getSecret());
req.addParameter("grant_type", "client_credentials");
req.setMethod("POST");
req.setPathInfo("/access_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return status OK", 200, res.getStatus());
String tokenJson = res.getContentAsString();
final JsonObject token = new JsonParser().parse(tokenJson).getAsJsonObject();
final String accessToken = token.get(ACCESS_TOKEN).getAsString();
Assert.assertTrue("response must be a valid json and have access_token field",
token.has(ACCESS_TOKEN) && accessToken.length() > 0);
Response result =
target("bennu-oauth").path("test").path("service-only-with-scope").queryParam(ACCESS_TOKEN, accessToken)
.request().get(Response.class);
Assert.assertNotEquals("request must fail", 200, result.getStatus());
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void testServiceOnlyWithScopeEndpoint() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
req.addParameter("client_id", serviceApplicationWithScope.getExternalId());
req.addParameter("client_secret", serviceApplicationWithScope.getSecret());
req.addParameter("grant_type", "client_credentials");
req.setMethod("POST");
req.setPathInfo("/access_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return status OK", 200, res.getStatus());
String tokenJson = res.getContentAsString();
final JsonObject token = new JsonParser().parse(tokenJson).getAsJsonObject();
final String accessToken = token.get(ACCESS_TOKEN).getAsString();
Assert.assertTrue("response must be a valid json and have access_token field",
token.has(ACCESS_TOKEN) && accessToken.length() > 0);
String result =
target("bennu-oauth").path("test").path("service-only-with-scope").queryParam(ACCESS_TOKEN, accessToken)
.request().get(String.class);
Assert.assertEquals("this is an endpoint with SERVICE scope, serviceOnly", result);
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void getServiceAccessTokenWithWrongGrantTypeTest() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
req.addParameter("client_id", serviceApplication.getExternalId());
req.addParameter("client_secret", serviceApplication.getSecret());
req.addParameter("grant_type", "authorization_code");
req.setMethod("POST");
req.setPathInfo("/access_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return status BAD_REQUEST", 400, res.getStatus());
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void getServiceAccessTokenWithWrongClientSecretTest() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
req.addParameter("client_id", serviceApplication.getExternalId());
req.addParameter(
"client_secret",
BaseEncoding.base64().encode(
(serviceApplication.getExternalId() + ":lasdlkasldksladkalskdsal").getBytes(StandardCharsets.UTF_8)));
req.addParameter("grant_type", "client_credentials");
req.setMethod("POST");
req.setPathInfo("/access_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return status BAD_REQUEST", 400, res.getStatus());
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void testOAuthServletAccessTokenRequestWithLoginExpired() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
Authenticate.unmock();
User user =
createUser("testOAuthServletAccessTokenRequestWithLoginExpired", "John", "Doe", "John Doe",
"john.doe@fenixedu.org");
user.closeLoginPeriod();
ExternalApplication externalApp = new ExternalApplication();
externalApp.setAuthor(user1);
externalApp.setName("Test External Application");
externalApp.setDescription("This is a test external application");
externalApp.setRedirectUrl("http://test.url/callback");
ApplicationUserSession applicationUserSession = new ApplicationUserSession();
applicationUserSession.setCode("fenixedu");
ApplicationUserAuthorization applicationUserAuthorization = new ApplicationUserAuthorization(user, externalApp);
applicationUserAuthorization.addSession(applicationUserSession);
externalApp.addApplicationUserAuthorization(applicationUserAuthorization);
String clientSecret = externalApp.getExternalId() + ":" + externalApp.getSecret();
req.addHeader(HttpHeaders.AUTHORIZATION,
"Basic " + Base64.getEncoder().encodeToString(clientSecret.getBytes(StandardCharsets.UTF_8)));
req.addParameter(REDIRECT_URI, externalApp.getRedirectUrl());
req.addParameter(CODE, applicationUserSession.getCode());
req.addParameter(GRANT_TYPE, GRANT_TYPE_AUTHORIZATION_CODE);
req.setMethod("POST");
req.setPathInfo("/access_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return bad request", Status.BAD_REQUEST.getStatusCode(), res.getStatus());
user.openLoginPeriod();
res = new MockHttpServletResponse();
oauthServlet.service(req, res);
final JsonObject token = new JsonParser().parse(res.getContentAsString()).getAsJsonObject();
Assert.assertTrue("response must be a valid json and have access_token field", token.has("access_token")
&& token.get("access_token").getAsString().length() > 0);
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void testOAuthServletRefreshTokenRequestWithLoginExpired() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
Authenticate.unmock();
User user =
createUser("testOAuthServletRefreshTokenRequestWithLoginExpired", "John", "Doe", "John Doe",
"john.doe@fenixedu.org");
user.closeLoginPeriod();
ExternalApplication externalApp = new ExternalApplication();
externalApp.setAuthor(user1);
externalApp.setName("Test External Application");
externalApp.setDescription("This is a test external application");
externalApp.setRedirectUrl("http://test.url/callback");
ApplicationUserSession applicationUserSession = new ApplicationUserSession();
applicationUserSession.setTokens(generateToken(applicationUserSession), generateToken(applicationUserSession));
ApplicationUserAuthorization applicationUserAuthorization = new ApplicationUserAuthorization(user, externalApp);
applicationUserAuthorization.addSession(applicationUserSession);
externalApp.addApplicationUserAuthorization(applicationUserAuthorization);
String clientSecret = externalApp.getExternalId() + ":" + externalApp.getSecret();
req.addHeader(HttpHeaders.AUTHORIZATION,
"Basic " + Base64.getEncoder().encodeToString(clientSecret.getBytes(StandardCharsets.UTF_8)));
req.addParameter(REFRESH_TOKEN, applicationUserSession.getRefreshToken());
req.addParameter(GRANT_TYPE, GRANT_TYPE_REFRESH_TOKEN);
req.setMethod("POST");
req.setPathInfo("/refresh_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return bad request", Status.BAD_REQUEST.getStatusCode(), res.getStatus());
user.openLoginPeriod();
res = new MockHttpServletResponse();
oauthServlet.service(req, res);
final JsonObject token = new JsonParser().parse(res.getContentAsString()).getAsJsonObject();
Assert.assertTrue("response must be a valid json and have access_token field", token.has("access_token")
&& token.get("access_token").getAsString().length() > 0);
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void testEndpointWithAccessTokenLoginExpired() {
User user = createUser("testEndpointWithAccessTokenLoginExpired", "John", "Doe", "John Doe", "john.doe@fenixedu.org");
Authenticate.unmock();
ExternalApplication externalApp = new ExternalApplication();
externalApp.setAuthor(user1);
externalApp.setName("Test External Application");
externalApp.setDescription("This is a test external application");
externalApp.setRedirectUrl("http://test.url/callback");
externalApp.addScopes(loggedScope);
ApplicationUserSession applicationUserSession = new ApplicationUserSession();
String accessToken = generateToken(applicationUserSession);
ApplicationUserAuthorization applicationUserAuthorization = new ApplicationUserAuthorization(user, externalApp);
externalApp.addApplicationUserAuthorization(applicationUserAuthorization);
applicationUserSession.setTokens(accessToken, null);
applicationUserAuthorization.addSession(applicationUserSession);
user.closeLoginPeriod();
Response responseKO =
target("bennu-oauth").path("test").path("test-scope-with-logged-user").queryParam("access_token", accessToken)
.request().get();
Assert.assertEquals(Status.UNAUTHORIZED, responseKO.getStatusInfo());
user.openLoginPeriod();
String result =
target("bennu-oauth").path("test").path("test-scope-with-logged-user").queryParam("access_token", accessToken)
.request().get(String.class);
Assert.assertEquals("this is an endpoint with TEST scope: testEndpointWithAccessTokenLoginExpired", result);
}
@Test
public void testServiceApplicationOAuthAccessProvider() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
Authenticate.unmock();
User user = createUser("testServiceApplicationOAuthAccessProvider", "John", "Doe", "John Doe", "john.doe@fenixedu.org");
ServiceApplication serviceApplication = new ServiceApplication();
serviceApplication.setAuthor(user1);
serviceApplication.addScopes(serviceApplicationOAuthAccessProvider);
serviceApplication.addScopes(loggedScope);
req.addParameter("client_id", serviceApplication.getExternalId());
req.addParameter("client_secret", serviceApplication.getSecret());
req.addParameter("grant_type", "client_credentials");
req.setMethod("POST");
req.setPathInfo("/access_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return status OK", 200, res.getStatus());
String tokenJson = res.getContentAsString();
final String serviceAccessToken =
new JsonParser().parse(tokenJson).getAsJsonObject().get("access_token").getAsString();
String result =
target("oauth").path("provider").path(serviceApplication.getExternalId()).path(user.getUsername())
.queryParam("access_token", serviceAccessToken).request().post(null, String.class);
Authenticate.unmock();
final String userAccessToken = new JsonParser().parse(result).getAsJsonObject().get("access_token").getAsString();
result =
target("bennu-oauth").path("test").path("test-scope-with-logged-user")
.queryParam("access_token", userAccessToken).request().get(String.class);
Assert.assertEquals("this is an endpoint with TEST scope: testServiceApplicationOAuthAccessProvider", result);
Authenticate.mock(user);
JsonArray authorizations =
target("bennu-oauth").path("authorizations").request().get(JsonElement.class).getAsJsonArray();
Assert.assertEquals("no authorizations because it is a service application", 0, authorizations.size());
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
} finally {
serviceApplication.removeScope(serviceApplicationOAuthAccessProvider);
serviceApplication.removeScope(loggedScope);
}
}
@Test
public void testServiceApplicationWithUnexistingScope() {
MockHttpServletRequest req = new MockHttpServletRequest();
MockHttpServletResponse res = new MockHttpServletResponse();
Authenticate.unmock();
User user = createUser("testServiceApplicationWithUnexistingScope", "John", "Doe", "John Doe", "john.doe@fenixedu.org");
ServiceApplication serviceApplication = new ServiceApplication();
serviceApplication.setAuthor(user);
req.addParameter("client_id", serviceApplication.getExternalId());
req.addParameter("client_secret", serviceApplication.getSecret());
req.addParameter("grant_type", "client_credentials");
req.setMethod("POST");
req.setPathInfo("/access_token");
try {
oauthServlet.service(req, res);
Assert.assertEquals("must return status OK", 200, res.getStatus());
String tokenJson = res.getContentAsString();
final String serviceAccessToken =
new JsonParser().parse(tokenJson).getAsJsonObject().get("access_token").getAsString();
Response response =
target("bennu-oauth").path("test").path("service-only-with-unexisting-scope")
.queryParam("access_token", serviceAccessToken).request().get();
Assert.assertNotEquals("request must fail since scope does not exist", 200, response.getStatus());
} catch (ServletException | IOException e) {
Assert.fail(e.getMessage());
}
}
@Test
public void testApplicationWithUnexistingScope() {
Authenticate.unmock();
User user = createUser("testApplicationWithUnexistingScope", "John", "Doe", "John Doe", "john.doe@fenixedu.org");
ExternalApplication externalApp = new ExternalApplication();
externalApp.setAuthor(user);
externalApp.setName("Test External Application");
externalApp.setDescription("This is a test external application");
externalApp.setRedirectUrl("http://test.url/callback");
ApplicationUserSession applicationUserSession = new ApplicationUserSession();
String accessToken = generateToken(applicationUserSession);
ApplicationUserAuthorization applicationUserAuthorization = new ApplicationUserAuthorization(user, externalApp);
externalApp.addApplicationUserAuthorization(applicationUserAuthorization);
applicationUserSession.setTokens(accessToken, null);
applicationUserAuthorization.addSession(applicationUserSession);
try {
target("bennu-oauth").path("test").path("test-scope-with-unexisting-scope").queryParam("access_token", accessToken)
.request().get(String.class);
} catch (WebApplicationException e) {
Assert.assertNotEquals("request must fail since scope does not exist", 200, e.getResponse().getStatus());
}
try {
target("bennu-oauth").path("test").path("service-only-with-unexisting-scope").queryParam("access_token", accessToken)
.request().get(String.class);
} catch (WebApplicationException e) {
Assert.assertNotEquals("request must fail since scope does not exist", 200, e.getResponse().getStatus());
}
}
}