Allow application/jwt media type for userinfo endpoint

Closes: https://github.com/keycloak/keycloak/issues/19346
This commit is contained in:
rmartinc 2023-03-28 10:25:39 +02:00 committed by Pedro Igor
parent 2e16be623e
commit 2bb9de1a8c
3 changed files with 35 additions and 13 deletions

View file

@ -121,7 +121,7 @@ public class UserInfoEndpoint {
@Path("/") @Path("/")
@GET @GET
@NoCache @NoCache
@Produces(javax.ws.rs.core.MediaType.APPLICATION_JSON) @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_JWT})
public Response issueUserInfoGet() { public Response issueUserInfoGet() {
setupCors(); setupCors();
String accessToken = this.appAuthManager.extractAuthorizationHeaderTokenOrReturnNull(session.getContext().getRequestHeaders()); String accessToken = this.appAuthManager.extractAuthorizationHeaderTokenOrReturnNull(session.getContext().getRequestHeaders());
@ -132,7 +132,7 @@ public class UserInfoEndpoint {
@Path("/") @Path("/")
@POST @POST
@NoCache @NoCache
@Produces(javax.ws.rs.core.MediaType.APPLICATION_JSON) @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_JWT})
public Response issueUserInfoPost() { public Response issueUserInfoPost() {
setupCors(); setupCors();

View file

@ -23,6 +23,7 @@ import org.keycloak.representations.UserInfo;
import org.keycloak.utils.MediaType; import org.keycloak.utils.MediaType;
import javax.ws.rs.client.Client; import javax.ws.rs.client.Client;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget; import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
@ -35,11 +36,18 @@ import java.net.URI;
public class UserInfoClientUtil { public class UserInfoClientUtil {
public static Response executeUserInfoRequest_getMethod(Client client, String accessToken) { public static Response executeUserInfoRequest_getMethod(Client client, String accessToken) {
return executeUserInfoRequest_getMethod(client, accessToken, null);
}
public static Response executeUserInfoRequest_getMethod(Client client, String accessToken, String acceptHeader) {
WebTarget userInfoTarget = getUserInfoWebTarget(client); WebTarget userInfoTarget = getUserInfoWebTarget(client);
return userInfoTarget.request() Invocation.Builder builder = userInfoTarget.request()
.header(HttpHeaders.AUTHORIZATION, "bearer " + accessToken) .header(HttpHeaders.AUTHORIZATION, "bearer " + accessToken);
.get(); if (acceptHeader != null) {
builder.header(HttpHeaders.ACCEPT, acceptHeader);
}
return builder.get();
} }
public static WebTarget getUserInfoWebTarget(Client client) { public static WebTarget getUserInfoWebTarget(Client client) {

View file

@ -75,6 +75,7 @@ import org.keycloak.testsuite.util.AdminClientUtil;
import org.keycloak.testsuite.util.ClientManager; import org.keycloak.testsuite.util.ClientManager;
import org.keycloak.testsuite.util.OAuthClient; import org.keycloak.testsuite.util.OAuthClient;
import org.keycloak.testsuite.util.RealmBuilder; import org.keycloak.testsuite.util.RealmBuilder;
import org.keycloak.testsuite.util.RoleBuilder;
import org.keycloak.testsuite.util.TokenSignatureUtil; import org.keycloak.testsuite.util.TokenSignatureUtil;
import org.keycloak.testsuite.util.UserInfoClientUtil; import org.keycloak.testsuite.util.UserInfoClientUtil;
import org.keycloak.testsuite.util.WaitUtils; import org.keycloak.testsuite.util.WaitUtils;
@ -107,7 +108,6 @@ import static org.junit.Assert.assertThat;
import static org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper.INCLUDE_IN_USERINFO; import static org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper.INCLUDE_IN_USERINFO;
import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson; import static org.keycloak.testsuite.admin.AbstractAdminTest.loadJson;
import static org.keycloak.testsuite.util.OAuthClient.AUTH_SERVER_ROOT; import static org.keycloak.testsuite.util.OAuthClient.AUTH_SERVER_ROOT;
import org.keycloak.testsuite.util.RoleBuilder;
/** /**
* @author pedroigor * @author pedroigor
@ -143,13 +143,12 @@ public class UserInfoTest extends AbstractKeycloakTest {
samlApp.setDirectAccessGrantsEnabled(true); samlApp.setDirectAccessGrantsEnabled(true);
} }
@Test public void testSuccessGet(String acceptHeader) throws Exception {
public void testSuccess_getMethod_header() throws Exception {
Client client = AdminClientUtil.createResteasyClient(); Client client = AdminClientUtil.createResteasyClient();
try { try {
AccessTokenResponse accessTokenResponse = executeGrantAccessTokenRequest(client); AccessTokenResponse accessTokenResponse = executeGrantAccessTokenRequest(client);
Response response = UserInfoClientUtil.executeUserInfoRequest_getMethod(client, accessTokenResponse.getToken()); Response response = UserInfoClientUtil.executeUserInfoRequest_getMethod(client, accessTokenResponse.getToken(), acceptHeader);
UserInfo userInfo = testSuccessfulUserInfoResponse(response); UserInfo userInfo = testSuccessfulUserInfoResponse(response);
testRolesAreNotInUserInfoResponse(userInfo); testRolesAreNotInUserInfoResponse(userInfo);
@ -159,6 +158,16 @@ public class UserInfoTest extends AbstractKeycloakTest {
} }
} }
@Test
public void testSuccess_getMethod_header() throws Exception {
testSuccessGet(null);
}
@Test
public void testSuccess_getMethod_header_accept_json() throws Exception {
testSuccessGet(MediaType.APPLICATION_JSON);
}
@Test @Test
public void testSuccess_postMethod_header() throws Exception { public void testSuccess_postMethod_header() throws Exception {
Client client = AdminClientUtil.createResteasyClient(); Client client = AdminClientUtil.createResteasyClient();
@ -473,12 +482,17 @@ public class UserInfoTest extends AbstractKeycloakTest {
@Test @Test
public void testSuccessSignedResponseES256() throws Exception { public void testSuccessSignedResponseES256() throws Exception {
testSuccessSignedResponse(Algorithm.ES256); testSuccessSignedResponse(Algorithm.ES256, null);
} }
@Test @Test
public void testSuccessSignedResponsePS256() throws Exception { public void testSuccessSignedResponsePS256() throws Exception {
testSuccessSignedResponse(Algorithm.PS256); testSuccessSignedResponse(Algorithm.PS256, null);
}
@Test
public void testSuccessSignedResponseRS256AcceptJWT() throws Exception {
testSuccessSignedResponse(Algorithm.RS256, MediaType.APPLICATION_JWT);
} }
@Test @Test
@ -920,7 +934,7 @@ public class UserInfoTest extends AbstractKeycloakTest {
return UserInfoClientUtil.testSuccessfulUserInfoResponse(response, "test-user@localhost", "test-user@localhost"); return UserInfoClientUtil.testSuccessfulUserInfoResponse(response, "test-user@localhost", "test-user@localhost");
} }
private void testSuccessSignedResponse(String sigAlg) throws Exception { private void testSuccessSignedResponse(String sigAlg, String acceptHeader) throws Exception {
try { try {
// Require signed userInfo request // Require signed userInfo request
@ -935,7 +949,7 @@ public class UserInfoTest extends AbstractKeycloakTest {
try { try {
AccessTokenResponse accessTokenResponse = executeGrantAccessTokenRequest(client); AccessTokenResponse accessTokenResponse = executeGrantAccessTokenRequest(client);
Response response = UserInfoClientUtil.executeUserInfoRequest_getMethod(client, accessTokenResponse.getToken()); Response response = UserInfoClientUtil.executeUserInfoRequest_getMethod(client, accessTokenResponse.getToken(), acceptHeader);
events.expect(EventType.USER_INFO_REQUEST) events.expect(EventType.USER_INFO_REQUEST)
.session(Matchers.notNullValue(String.class)) .session(Matchers.notNullValue(String.class))