diff --git a/openid-standalone-it/pom.xml b/openid-standalone-it/pom.xml
index 75521c4c..7298eae4 100644
--- a/openid-standalone-it/pom.xml
+++ b/openid-standalone-it/pom.xml
@@ -86,6 +86,12 @@
+
+ fish.payara.security.connectors
+ security-connectors-api
+ ${project.version}
+ provided
+
fish.payara.security.connectors
openid-standalone
@@ -178,6 +184,12 @@
arquillian-payara-server-remote
test
+
+
+ jakarta.xml.bind
+ jakarta.xml.bind-api
+ runtime
+
diff --git a/openid-standalone-it/src/main/java/fish/payara/security/openid/idp/AbstractIdProvider.java b/openid-standalone-it/src/main/java/fish/payara/security/openid/idp/AbstractIdProvider.java
index ba6a4e7d..de8d62a2 100644
--- a/openid-standalone-it/src/main/java/fish/payara/security/openid/idp/AbstractIdProvider.java
+++ b/openid-standalone-it/src/main/java/fish/payara/security/openid/idp/AbstractIdProvider.java
@@ -180,9 +180,8 @@ public Response authEndpoint(@BeanParam AuthRequest authRequest) throws URISynta
@Path("token")
@POST
@Consumes(APPLICATION_FORM_URLENCODED)
- public Response tokenEndpoint(@BeanParam TokenRequest tokenRequest, MultivaluedMap allParams) {
- //TokenRequest tokenRequest = new TokenRequest(allParams);
- tokenRequest.allParams = allParams;
+ public Response tokenEndpoint(MultivaluedMap allParams) {
+ TokenRequest tokenRequest = new TokenRequest(allParams);
try {
Token result;
@@ -434,6 +433,7 @@ public TokenRequest() {
public TokenRequest(MultivaluedMap allParams) {
this.allParams = allParams;
+ code = allParams.getFirst(CODE);
clientId = allParams.getFirst(CLIENT_ID);
clientSecret = allParams.getFirst(CLIENT_SECRET);
grantType = allParams.getFirst(GRANT_TYPE);
diff --git a/openid-standalone-it/src/main/java/fish/payara/security/openid/idp/NaiveCookieManager.java b/openid-standalone-it/src/main/java/fish/payara/security/openid/idp/NaiveCookieManager.java
new file mode 100644
index 00000000..800e111e
--- /dev/null
+++ b/openid-standalone-it/src/main/java/fish/payara/security/openid/idp/NaiveCookieManager.java
@@ -0,0 +1,82 @@
+/*
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2022 Payara Foundation and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://github.com/payara/Payara/blob/master/LICENSE.txt
+ * See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at glassfish/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * The Payara Foundation designates this particular file as subject to the "Classpath"
+ * exception as provided by the Payara Foundation in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ *
+ */
+
+package fish.payara.security.openid.idp;
+
+import java.io.IOException;
+import java.net.URI;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.ws.rs.client.ClientRequestContext;
+import javax.ws.rs.client.ClientRequestFilter;
+import javax.ws.rs.client.ClientResponseContext;
+import javax.ws.rs.client.ClientResponseFilter;
+import javax.ws.rs.core.Cookie;
+import javax.ws.rs.core.NewCookie;
+
+public class NaiveCookieManager implements ClientRequestFilter, ClientResponseFilter {
+ private static Map cookies = new ConcurrentHashMap<>();
+
+ @Override
+ public void filter(ClientRequestContext requestContext) throws IOException {
+ for (Cookie cookie : cookies.values()) {
+ if (matchesDomain(requestContext.getUri(), cookie)) {
+ requestContext.getHeaders().add("Cookie", cookie.toString());
+ }
+ }
+ }
+
+ private boolean matchesDomain(URI uri, Cookie cookie) {
+ // let's not think about domains right now
+ return uri.getPath().startsWith(cookie.getPath());
+ }
+
+
+ @Override
+ public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
+ for (NewCookie cookie : responseContext.getCookies().values()) {
+ Cookie c = new Cookie(cookie.getName(), cookie.getValue(), cookie.getPath(), cookie.getDomain(), cookie.getVersion());
+ cookies.put(c.getDomain() + "/" + c.getName(), c);
+ }
+ }
+}
diff --git a/openid-standalone-it/src/test/java/fish/payara/security/openid/adfs/AdfsAuth.java b/openid-standalone-it/src/test/java/fish/payara/security/openid/adfs/AdfsAuth.java
index 1a07c669..6d18b5d9 100644
--- a/openid-standalone-it/src/test/java/fish/payara/security/openid/adfs/AdfsAuth.java
+++ b/openid-standalone-it/src/test/java/fish/payara/security/openid/adfs/AdfsAuth.java
@@ -59,10 +59,10 @@
clientId = "test_client",
clientSecret = "test_client",
providerURI = "#{urlExtractor.providerUrl}",
- useSession = false,
providerMetadata = @OpenIdProviderMetadata(
accessTokenIssuer = "http://someone-else"
- )
+ ),
+ userClaimsFromIDToken = true
)
@Path("client")
@RolesAllowed("authenticated")
diff --git a/openid-standalone-it/src/test/java/fish/payara/security/openid/adfs/AdfsEmulation.java b/openid-standalone-it/src/test/java/fish/payara/security/openid/adfs/AdfsEmulation.java
index c63e07fe..9321feec 100644
--- a/openid-standalone-it/src/test/java/fish/payara/security/openid/adfs/AdfsEmulation.java
+++ b/openid-standalone-it/src/test/java/fish/payara/security/openid/adfs/AdfsEmulation.java
@@ -43,6 +43,7 @@
package fish.payara.security.openid.adfs;
import java.net.URI;
+import java.util.Arrays;
import java.util.Date;
import javax.json.JsonObject;
@@ -93,7 +94,8 @@ protected Token exchangeToken(TokenRequest request) throws AuthException {
@Override
protected Token exchangeToken(AuthCode code) throws AuthException {
Token result = new Token();
- result.setIdToken(result.claimsFor(code, providerRoot(uriInfo), "test_object"));
+ result.setIdToken(result.claimsFor(code, providerRoot(uriInfo).resolve("idp/"), "test_object").claim("groups", Arrays.asList("authenticated",
+ "code_exchange")));
result.setAccessToken(result.claimsFor(code, URI.create("http://someone-else"), "test_object"));
return result;
}
@@ -110,6 +112,6 @@ protected JWKSet getKeyset() {
@Override
protected JsonObject userInfo(Token token) {
- throw new NotAuthorizedException("ADFS throws 401 here", (Response) null);
+ throw new NotAuthorizedException("ADFS throws 401 here", Response.status(401).build());
}
}
diff --git a/openid-standalone-it/src/test/java/fish/payara/security/openid/adfs/AdfsEmulationIT.java b/openid-standalone-it/src/test/java/fish/payara/security/openid/adfs/AdfsEmulationIT.java
index 6e8f2e64..5e816e4e 100644
--- a/openid-standalone-it/src/test/java/fish/payara/security/openid/adfs/AdfsEmulationIT.java
+++ b/openid-standalone-it/src/test/java/fish/payara/security/openid/adfs/AdfsEmulationIT.java
@@ -45,14 +45,19 @@
import java.io.IOException;
import java.net.URI;
+import javax.json.Json;
+import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Form;
+import javax.ws.rs.core.Response;
+import fish.payara.arquillian.jersey.client.ClientProperties;
import fish.payara.security.openid.idp.LogExceptionOnServerSide;
+import fish.payara.security.openid.idp.NaiveCookieManager;
import fish.payara.security.openid.idp.OpenIdDeployment;
import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.junit5.ArquillianExtension;
@@ -69,7 +74,7 @@ public class AdfsEmulationIT {
@Deployment
public static WebArchive deployment() {
return OpenIdDeployment.withAbstractProvider().addClasses(JaxrsApplication.class, AdfsEmulation.class, AdfsAuth.class,
- AccessTokenRoleMapping.class, UrlExtractor.class);
+ AccessTokenRoleMapping.class, UrlExtractor.class, OpenIdCallback.class, NaiveCookieManager.class);
}
@ArquillianResource
@@ -85,4 +90,27 @@ public void accessTokenGetsAccepted() throws IOException {
String myself = base.path("client").request().header("Authorization", "Bearer " + accessToken).get(String.class);
assertEquals("test_subject", myself);
}
+
+ @Test
+ public void userInfoEndpointIsNotTouched() {
+ Client client = ClientBuilder.newClient().register(new NaiveCookieManager()).property(ClientProperties.FOLLOW_REDIRECTS, false);
+
+ WebTarget base = client.target(baseUri);
+ // this request redirects takes client to code authorization endpoint, and gets redirected to openid callback
+ // we need to manually follow these redirects otherwise our naive cookie manager will not collect relevant cookies
+ // to identify ourselves when we land back at callback
+
+ // client redirects us to idp code
+ Response response = base.path("client").request().get();
+ assertEquals(Response.Status.Family.REDIRECTION, response.getStatusInfo().getFamily());
+
+ // code redirects to OAuth callback
+ response = client.target(response.getLocation()).request().get();
+ assertEquals(Response.Status.Family.REDIRECTION, response.getStatusInfo().getFamily());
+
+ // oauth callback returns list of groups for us
+ response = client.target(response.getLocation()).request().get();
+ JsonArray groups = response.readEntity(JsonArray.class);
+ assertEquals(Json.createArrayBuilder().add("authenticated").add("code_exchange").build(), groups);
+ }
}
diff --git a/openid-standalone-it/src/test/java/fish/payara/security/openid/adfs/OpenIdCallback.java b/openid-standalone-it/src/test/java/fish/payara/security/openid/adfs/OpenIdCallback.java
new file mode 100644
index 00000000..9076988a
--- /dev/null
+++ b/openid-standalone-it/src/test/java/fish/payara/security/openid/adfs/OpenIdCallback.java
@@ -0,0 +1,78 @@
+/*
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2022 Payara Foundation and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://github.com/payara/Payara/blob/master/LICENSE.txt
+ * See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at glassfish/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * The Payara Foundation designates this particular file as subject to the "Classpath"
+ * exception as provided by the Payara Foundation in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ *
+ */
+
+package fish.payara.security.openid.adfs;
+
+import java.security.Principal;
+import java.util.logging.Logger;
+
+import javax.enterprise.context.RequestScoped;
+import javax.inject.Inject;
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+
+import fish.payara.security.connectors.openid.api.OpenIdContext;
+
+import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
+
+@Path("Callback")
+@RequestScoped
+public class OpenIdCallback {
+ private static final Logger LOGGER = Logger.getLogger(OpenIdCallback.class.getName());
+
+ @Inject
+ Principal principal;
+
+ @Inject
+ OpenIdContext context;
+
+ @GET
+ @Produces(APPLICATION_JSON)
+ public JsonArray userGroups() {
+ LOGGER.info("Request of " + principal.getName());
+ LOGGER.info("Request of " + context.getSubject());
+ return Json.createArrayBuilder(context.getCallerGroups()).build();
+ }
+}