Perform internal introspect for the access token in the account app

Closes #27243

Signed-off-by: rmartinc <rmartinc@redhat.com>
This commit is contained in:
rmartinc 2024-02-26 08:48:37 +01:00 committed by Marek Posolda
parent 004805e21d
commit 562decde35
3 changed files with 77 additions and 6 deletions

View file

@ -61,6 +61,7 @@ public class AccessTokenIntrospectionProvider implements TokenIntrospectionProvi
this.tokenManager = new TokenManager();
}
@Override
public Response introspect(String token, EventBuilder eventBuilder) {
AccessToken accessToken = null;
try {
@ -123,7 +124,7 @@ public class AccessTokenIntrospectionProvider implements TokenIntrospectionProvi
}
}
private AccessToken transformAccessToken(AccessToken token) {
public AccessToken transformAccessToken(AccessToken token) {
if (token == null) {
return null;
}

View file

@ -17,7 +17,6 @@
package org.keycloak.services.resources.account;
import org.jboss.logging.Logger;
import org.keycloak.common.Profile;
import org.keycloak.http.HttpRequest;
import org.keycloak.http.HttpResponse;
import org.keycloak.common.enums.AccountRestApiVersion;
@ -26,6 +25,10 @@ import org.keycloak.models.ClientModel;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.protocol.oidc.AccessTokenIntrospectionProvider;
import org.keycloak.protocol.oidc.AccessTokenIntrospectionProviderFactory;
import org.keycloak.protocol.oidc.TokenIntrospectionProvider;
import org.keycloak.representations.AccessToken;
import org.keycloak.services.cors.Cors;
import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.Auth;
@ -109,16 +112,26 @@ public class AccountLoader {
}
}
private AccountRestService getAccountRestService(ClientModel client, String versionStr) {
AuthenticationManager.AuthResult authResult = new AppAuthManager.BearerTokenAuthenticator(session)
.setAudience(client.getClientId())
.authenticate();
if (authResult == null) {
throw new NotAuthorizedException("Bearer token required");
}
Auth auth = new Auth(session.getContext().getRealm(), authResult.getToken(), authResult.getUser(), client, authResult.getSession(), false);
AccessToken accessToken = authResult.getToken();
if (accessToken.getAudience() == null || accessToken.getResourceAccess(client.getClientId()) == null) {
// transform for introspection to get the required claims
AccessTokenIntrospectionProvider provider = (AccessTokenIntrospectionProvider) session.getProvider(TokenIntrospectionProvider.class,
AccessTokenIntrospectionProviderFactory.ACCESS_TOKEN_TYPE);
accessToken = provider.transformAccessToken(accessToken);
}
if (!accessToken.hasAudience(client.getClientId())) {
throw new NotAuthorizedException("Invalid audience for client " + client.getClientId());
}
Auth auth = new Auth(session.getContext().getRealm(), accessToken, authResult.getUser(), client, authResult.getSession(), false);
Cors.add(request).allowedOrigins(auth.getToken()).allowedMethods("GET", "PUT", "POST", "DELETE").auth().build(response);

View file

@ -0,0 +1,57 @@
/*
* Copyright 2024 Red Hat, Inc. and/or its affiliates
* and other contributors as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.keycloak.testsuite.account;
import org.keycloak.models.Constants;
import org.keycloak.representations.idm.ClientPoliciesRepresentation;
import org.keycloak.representations.idm.ClientPolicyConditionConfigurationRepresentation;
import org.keycloak.representations.idm.ClientProfilesRepresentation;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.services.clientpolicy.condition.AnyClientConditionFactory;
import org.keycloak.services.clientpolicy.executor.UseLightweightAccessTokenExecutorFactory;
import org.keycloak.testsuite.util.ClientPoliciesUtil.ClientPoliciesBuilder;
import org.keycloak.testsuite.util.ClientPoliciesUtil.ClientPolicyBuilder;
import org.keycloak.testsuite.util.ClientPoliciesUtil.ClientProfileBuilder;
import org.keycloak.testsuite.util.ClientPoliciesUtil.ClientProfilesBuilder;
/**
*
* @author rmartinc
*/
public class AccountRestServiceLightweightTokenTest extends AccountRestServiceTest {
@Override
public void configureTestRealm(RealmRepresentation testRealm) {
super.configureTestRealm(testRealm);
try {
// enable lightweight tokens for any client in the realm
ClientProfilesRepresentation profiles = new ClientProfilesBuilder().addProfile(
new ClientProfileBuilder().createProfile("enable lightweight tokens", "Profile Lightweight Tokens")
.addExecutor(UseLightweightAccessTokenExecutorFactory.PROVIDER_ID, null).toRepresentation()).toRepresentation();
ClientPoliciesRepresentation policies = new ClientPoliciesBuilder().addPolicy(
new ClientPolicyBuilder().createPolicy("enable lightweight tokens", "Policy Lightweight Tokens", true)
.addCondition(AnyClientConditionFactory.PROVIDER_ID, new ClientPolicyConditionConfigurationRepresentation())
.addProfile("enable lightweight tokens")
.toRepresentation()).toRepresentation();
testRealm.setParsedClientProfiles(profiles);
testRealm.setParsedClientPolicies(policies);
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
}