Skip to content

Commit

Permalink
Enhancing Lightweight access token M2(keycloak#25716)
Browse files Browse the repository at this point in the history
Closes keycloak#23724

Signed-off-by: shigeyuki kabano <[email protected]>
Signed-off-by: Stefan Wiedemann <[email protected]>
  • Loading branch information
skabano authored and wistefan committed Jan 17, 2024
1 parent b9dea5f commit 7edf8ed
Show file tree
Hide file tree
Showing 10 changed files with 378 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2968,4 +2968,6 @@ referralHelp=Specifies if LDAP referrals should be followed or ignored. Please n
authenticatorRefConfig.value.help=Add a custom reference name for the authenticator. When this authenticator is successfully completed during an authentication flow, the Authentication Method Reference (AMR) protocol mapper will use this value to populate the amr claim of the generated tokens. Note, the AMR protocol must be configured for the given client to populate the AMR claim
authenticatorRefConfig.value.label=Authenticator Reference
authenticatorRefConfig.maxAge.help=The max age in seconds that the authenticator reference value is good for in an SSO session. When the Authentication Method Reference (AMR) protocol mapper is used, the AMR will only be considered valid and populated in the token if the authenticator execution was completed within the specified max age.
authenticatorRefConfig.maxAge.label=Authenticator Reference Max Age
authenticatorRefConfig.maxAge.label=Authenticator Reference Max Age
includeInLightweight.label=Add to lightweight access token
includeInLightweight.tooltip=Should the claim be added to the lightweight access token?
Original file line number Diff line number Diff line change
Expand Up @@ -163,4 +163,5 @@ public final class Constants {

public static final String SESSION_NOTE_LIGHTWEIGHT_USER = "keycloak.userModel";

public static final String USE_LIGHTWEIGHT_ACCESS_TOKEN_ENABLED = "client.use.lightweight.access.token.enabled";
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import org.keycloak.Config;
import org.keycloak.models.ClientSessionContext;
import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.ProtocolMapperModel;
Expand Down Expand Up @@ -80,10 +81,16 @@ public AccessToken transformUserInfoToken(AccessToken token, ProtocolMapperModel
return token;
}

boolean getShouldUseLightweightToken(KeycloakSession session) {
Object attributeValue = session.getAttribute(Constants.USE_LIGHTWEIGHT_ACCESS_TOKEN_ENABLED);
return (attributeValue != null) ? (boolean) attributeValue : false;
}

public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
UserSessionModel userSession, ClientSessionContext clientSessionCtx) {

if (!OIDCAttributeMapperHelper.includeInAccessToken(mappingModel)){
boolean shouldUseLightweightToken = getShouldUseLightweightToken(session);
boolean includeInAccessToken = shouldUseLightweightToken ? OIDCAttributeMapperHelper.includeInLightweightAccessToken(mappingModel) : OIDCAttributeMapperHelper.includeInAccessToken(mappingModel);
if (!includeInAccessToken){
return token;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,9 @@ public String getHelpText() {
@Override
public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
UserSessionModel userSession, ClientSessionContext clientSessionCtx) {

if (!includeInAccessToken(mappingModel)){
boolean shouldUseLightweightToken = getShouldUseLightweightToken(session);
boolean includeInAccessToken = shouldUseLightweightToken ? OIDCAttributeMapperHelper.includeInLightweightAccessToken(mappingModel) : includeInAccessToken(mappingModel);
if (!includeInAccessToken){
return token;
}
setWebOrigin(token, session, clientSessionCtx);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ public int getPriority() {
@Override
public AccessToken transformAccessToken(AccessToken token, ProtocolMapperModel mappingModel, KeycloakSession session,
UserSessionModel userSession, ClientSessionContext clientSessionCtx) {
if (!includeInAccessToken(mappingModel)){
boolean shouldUseLightweightToken = getShouldUseLightweightToken(session);
boolean includeInAccessToken = shouldUseLightweightToken ? OIDCAttributeMapperHelper.includeInLightweightAccessToken(mappingModel) : includeInAccessToken(mappingModel);
if (!includeInAccessToken){
return token;
}
setAudience(token, clientSessionCtx, session);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ public class OIDCAttributeMapperHelper {
public static final String INCLUDE_IN_INTROSPECTION_LABEL = "includeInIntrospection.label";
public static final String INCLUDE_IN_INTROSPECTION_HELP_TEXT = "includeInIntrospection.tooltip";

public static final String INCLUDE_IN_LIGHTWEIGHT_ACCESS_TOKEN = "lightweight.claim";

public static final String INCLUDE_IN_LIGHTWEIGHT_ACCESS_TOKEN_LABEL = "includeInLightweight.label";

public static final String INCLUDE_IN_LIGHTWEIGHT_ACCESS_TOKEN_HELP_TEXT = "includeInLightweight.tooltip";

private static final Logger logger = Logger.getLogger(OIDCAttributeMapperHelper.class);

/**
Expand Down Expand Up @@ -392,6 +398,10 @@ public static boolean includeInIntrospection(ProtocolMapperModel mappingModel) {
return "true".equals(includeInIntrospection);
}

public static boolean includeInLightweightAccessToken(ProtocolMapperModel mappingModel) {
return "true".equals(mappingModel.getConfig().get(INCLUDE_IN_LIGHTWEIGHT_ACCESS_TOKEN));
}

public static void addAttributeConfig(List<ProviderConfigProperty> configProperties, Class<? extends ProtocolMapper> protocolMapperClass) {
addTokenClaimNameConfig(configProperties);
addJsonTypeConfig(configProperties);
Expand Down Expand Up @@ -443,6 +453,14 @@ public static void addIncludeInTokensConfig(List<ProviderConfigProperty> configP
property.setDefaultValue("true");
property.setHelpText(INCLUDE_IN_ACCESS_TOKEN_HELP_TEXT);
configProperties.add(property);

ProviderConfigProperty property2 = new ProviderConfigProperty();
property2.setName(INCLUDE_IN_LIGHTWEIGHT_ACCESS_TOKEN);
property2.setLabel(INCLUDE_IN_LIGHTWEIGHT_ACCESS_TOKEN_LABEL);
property2.setType(ProviderConfigProperty.BOOLEAN_TYPE);
property2.setDefaultValue("false");
property2.setHelpText(INCLUDE_IN_LIGHTWEIGHT_ACCESS_TOKEN_HELP_TEXT);
configProperties.add(property2);
}

if (UserInfoTokenMapper.class.isAssignableFrom(protocolMapperClass)) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2023 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.services.clientpolicy.executor;

import org.keycloak.models.Constants;
import org.keycloak.models.KeycloakSession;
import org.keycloak.representations.idm.ClientPolicyExecutorConfigurationRepresentation;
import org.keycloak.services.clientpolicy.ClientPolicyContext;
import org.keycloak.services.clientpolicy.ClientPolicyException;

public class UseLightweightAccessTokenExecutor implements ClientPolicyExecutorProvider<ClientPolicyExecutorConfigurationRepresentation> {
private final KeycloakSession session;

public UseLightweightAccessTokenExecutor(KeycloakSession session) {
this.session = session;
}

@Override
public String getProviderId() {
return UseLightweightAccessTokenExecutorFactory.PROVIDER_ID;
}

@Override
public void executeOnEvent(ClientPolicyContext context) throws ClientPolicyException {
switch (context.getEvent()) {
case TOKEN_REQUEST:
case TOKEN_REFRESH:
case RESOURCE_OWNER_PASSWORD_CREDENTIALS_REQUEST:
case SERVICE_ACCOUNT_TOKEN_REQUEST:
case BACKCHANNEL_TOKEN_REQUEST:
case DEVICE_TOKEN_REQUEST:
session.setAttribute(Constants.USE_LIGHTWEIGHT_ACCESS_TOKEN_ENABLED, true);
break;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2023 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.services.clientpolicy.executor;

import org.keycloak.Config;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.provider.ProviderConfigProperty;

import java.util.Collections;
import java.util.List;

public class UseLightweightAccessTokenExecutorFactory implements ClientPolicyExecutorProviderFactory {
public static final String PROVIDER_ID = "use-lightweight-access-token";

@Override
public String getHelpText() {
return "Use lightweight access token";
}

@Override
public List<ProviderConfigProperty> getConfigProperties() {
return Collections.emptyList();
}

@Override
public ClientPolicyExecutorProvider create(KeycloakSession session) {
return new UseLightweightAccessTokenExecutor(session);
}

@Override
public void init(Config.Scope config) {

}

@Override
public void postInit(KeycloakSessionFactory factory) {

}

@Override
public void close() {

}

@Override
public String getId() {
return PROVIDER_ID;
}

@Override
public boolean isSupported() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ org.keycloak.services.clientpolicy.executor.SuppressRefreshTokenRotationExecutor
org.keycloak.services.clientpolicy.executor.RegistrationAccessTokenRotationDisabledExecutorFactory
org.keycloak.services.clientpolicy.executor.RejectImplicitGrantExecutorFactory
org.keycloak.services.clientpolicy.executor.SecureParContentsExecutorFactory
org.keycloak.services.clientpolicy.executor.DPoPBindEnforcerExecutorFactory
org.keycloak.services.clientpolicy.executor.DPoPBindEnforcerExecutorFactory
org.keycloak.services.clientpolicy.executor.UseLightweightAccessTokenExecutorFactory
Loading

0 comments on commit 7edf8ed

Please sign in to comment.