KEYCLOAK-8838 Incorrect resource_access in accessToken when clientId contains dots
This commit is contained in:
parent
3c44e6c377
commit
1237986fd0
2 changed files with 61 additions and 0 deletions
|
@ -82,6 +82,9 @@ abstract class AbstractUserRoleMappingMapper extends AbstractOIDCProtocolMapper
|
|||
|
||||
private static final Pattern CLIENT_ID_PATTERN = Pattern.compile("\\$\\{client_id\\}");
|
||||
|
||||
private static final Pattern DOT_PATTERN = Pattern.compile("\\.");
|
||||
private static final String DOT_REPLACEMENT = "\\\\\\\\.";
|
||||
|
||||
private static void mapClaim(IDToken token, ProtocolMapperModel mappingModel, Object attributeValue, String clientId) {
|
||||
attributeValue = OIDCAttributeMapperHelper.mapAttributeValue(mappingModel, attributeValue);
|
||||
if (attributeValue == null) return;
|
||||
|
@ -92,6 +95,8 @@ abstract class AbstractUserRoleMappingMapper extends AbstractOIDCProtocolMapper
|
|||
}
|
||||
|
||||
if (clientId != null) {
|
||||
// case when clientId contains dots
|
||||
clientId = DOT_PATTERN.matcher(clientId).replaceAll(DOT_REPLACEMENT);
|
||||
protocolClaim = CLIENT_ID_PATTERN.matcher(protocolClaim).replaceAll(clientId);
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@ import org.junit.Rule;
|
|||
import org.junit.Test;
|
||||
import org.keycloak.OAuth2Constants;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.admin.client.resource.UserResource;
|
||||
import org.keycloak.common.util.PemUtils;
|
||||
import org.keycloak.events.Details;
|
||||
import org.keycloak.events.Errors;
|
||||
|
@ -29,6 +31,8 @@ import org.keycloak.events.EventType;
|
|||
import org.keycloak.jose.jws.Algorithm;
|
||||
import org.keycloak.jose.jws.JWSInput;
|
||||
import org.keycloak.jose.jws.crypto.RSAProvider;
|
||||
import org.keycloak.representations.AccessToken;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.testsuite.util.KeycloakModelUtils;
|
||||
import org.keycloak.protocol.oidc.OIDCAdvancedConfigWrapper;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
|
||||
|
@ -42,6 +46,7 @@ import org.keycloak.testsuite.Assert;
|
|||
import org.keycloak.testsuite.AssertEvents;
|
||||
import org.keycloak.testsuite.admin.ApiUtil;
|
||||
import org.keycloak.testsuite.util.ClientManager;
|
||||
import org.keycloak.testsuite.util.OAuthClient;
|
||||
import org.keycloak.testsuite.util.RealmBuilder;
|
||||
import org.keycloak.testsuite.util.TokenSignatureUtil;
|
||||
import org.keycloak.testsuite.util.UserInfoClientUtil;
|
||||
|
@ -60,6 +65,7 @@ import javax.ws.rs.core.Response.Status;
|
|||
import javax.ws.rs.core.UriBuilder;
|
||||
import java.net.URI;
|
||||
import java.security.PublicKey;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
@ -152,6 +158,51 @@ public class UserInfoTest extends AbstractKeycloakTest {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// KEYCLOAK-8838
|
||||
@Test
|
||||
public void testSuccess_dotsInClientId() throws Exception {
|
||||
// Create client with dot in the name and with some role
|
||||
ClientRepresentation clientRep = org.keycloak.testsuite.util.ClientBuilder.create()
|
||||
.clientId("my.foo.client")
|
||||
.addRedirectUri("http://foo.host")
|
||||
.secret("password")
|
||||
.directAccessGrants()
|
||||
.defaultRoles("my.foo.role")
|
||||
.build();
|
||||
|
||||
RealmResource realm = adminClient.realm("test");
|
||||
|
||||
Response resp = realm.clients().create(clientRep);
|
||||
String clientUUID = ApiUtil.getCreatedId(resp);
|
||||
resp.close();
|
||||
getCleanup().addClientUuid(clientUUID);
|
||||
|
||||
// Assign role to the user
|
||||
RoleRepresentation fooRole = realm.clients().get(clientUUID).roles().get("my.foo.role").toRepresentation();
|
||||
UserResource userResource = ApiUtil.findUserByUsernameId(realm, "test-user@localhost");
|
||||
userResource.roles().clientLevel(clientUUID).add(Collections.singletonList(fooRole));
|
||||
|
||||
// Login to the new client
|
||||
OAuthClient.AccessTokenResponse accessTokenResponse = oauth.clientId("my.foo.client")
|
||||
.doGrantAccessTokenRequest("password", "test-user@localhost", "password");
|
||||
|
||||
AccessToken accessToken = oauth.verifyToken(accessTokenResponse.getAccessToken());
|
||||
Assert.assertNames(accessToken.getResourceAccess("my.foo.client").getRoles(), "my.foo.role");
|
||||
|
||||
events.clear();
|
||||
|
||||
// Send UserInfo request and ensure it is correct
|
||||
Client client = ClientBuilder.newClient();
|
||||
try {
|
||||
Response response = UserInfoClientUtil.executeUserInfoRequest_getMethod(client, accessTokenResponse.getAccessToken());
|
||||
|
||||
testSuccessfulUserInfoResponse(response, "my.foo.client");
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_postMethod_header_textEntity() throws Exception {
|
||||
Client client = ClientBuilder.newClient();
|
||||
|
@ -418,11 +469,16 @@ public class UserInfoTest extends AbstractKeycloakTest {
|
|||
}
|
||||
|
||||
private void testSuccessfulUserInfoResponse(Response response) {
|
||||
testSuccessfulUserInfoResponse(response, "test-app");
|
||||
}
|
||||
|
||||
private void testSuccessfulUserInfoResponse(Response response, String expectedClientId) {
|
||||
events.expect(EventType.USER_INFO_REQUEST)
|
||||
.session(Matchers.notNullValue(String.class))
|
||||
.detail(Details.AUTH_METHOD, Details.VALIDATE_ACCESS_TOKEN)
|
||||
.detail(Details.USERNAME, "test-user@localhost")
|
||||
.detail(Details.SIGNATURE_REQUIRED, "false")
|
||||
.client(expectedClientId)
|
||||
.assertEvent();
|
||||
UserInfoClientUtil.testSuccessfulUserInfoResponse(response, "test-user@localhost", "test-user@localhost");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue