-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add new JWT profile that rename 'groups' claim with 'roles' (#637)
This PR adds a 'kc' profile which aim is allowing the integration with a Keycloak environment by having "roles" claim instead of "groups".
- Loading branch information
1 parent
952692a
commit 283d791
Showing
18 changed files
with
901 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
32 changes: 32 additions & 0 deletions
32
...service/src/main/java/it/infn/mw/iam/core/oauth/profile/keycloak/KeycloakGroupHelper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/** | ||
* Copyright (c) Istituto Nazionale di Fisica Nucleare (INFN). 2016-2021 | ||
* | ||
* 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 it.infn.mw.iam.core.oauth.profile.keycloak; | ||
|
||
import java.util.Set; | ||
import java.util.stream.Collectors; | ||
|
||
import it.infn.mw.iam.persistence.model.IamUserInfo; | ||
|
||
public class KeycloakGroupHelper { | ||
|
||
public static final String KEYCLOAK_ROLES_CLAIM = "roles"; | ||
|
||
public Set<String> resolveGroupNames(IamUserInfo userInfo) { | ||
|
||
return userInfo.getGroups().stream().map(g -> g.getName()).collect(Collectors.toSet()); | ||
} | ||
|
||
} |
66 changes: 66 additions & 0 deletions
66
...e/src/main/java/it/infn/mw/iam/core/oauth/profile/keycloak/KeycloakIdTokenCustomizer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/** | ||
* Copyright (c) Istituto Nazionale di Fisica Nucleare (INFN). 2016-2021 | ||
* | ||
* 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 it.infn.mw.iam.core.oauth.profile.keycloak; | ||
|
||
import java.util.Set; | ||
|
||
import org.mitre.oauth2.model.ClientDetailsEntity; | ||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity; | ||
import org.mitre.openid.connect.service.ScopeClaimTranslationService; | ||
import org.springframework.security.oauth2.provider.OAuth2Request; | ||
|
||
import com.nimbusds.jwt.JWTClaimsSet.Builder; | ||
|
||
import it.infn.mw.iam.config.IamProperties; | ||
import it.infn.mw.iam.core.oauth.profile.iam.ClaimValueHelper; | ||
import it.infn.mw.iam.core.oauth.profile.iam.IamJWTProfileIdTokenCustomizer; | ||
import it.infn.mw.iam.persistence.model.IamAccount; | ||
import it.infn.mw.iam.persistence.model.IamUserInfo; | ||
import it.infn.mw.iam.persistence.repository.IamAccountRepository; | ||
|
||
@SuppressWarnings("deprecation") | ||
public class KeycloakIdTokenCustomizer extends IamJWTProfileIdTokenCustomizer { | ||
|
||
private final KeycloakGroupHelper groupHelper; | ||
|
||
public KeycloakIdTokenCustomizer(IamAccountRepository accountRepo, | ||
ScopeClaimTranslationService scopeClaimConverter, ClaimValueHelper claimValueHelper, | ||
KeycloakGroupHelper groupHelper, IamProperties properties) { | ||
super(accountRepo, scopeClaimConverter, claimValueHelper, properties); | ||
this.groupHelper = groupHelper; | ||
} | ||
|
||
@Override | ||
public void customizeIdTokenClaims(Builder idClaims, ClientDetailsEntity client, | ||
OAuth2Request request, String sub, OAuth2AccessTokenEntity accessToken, IamAccount account) { | ||
|
||
super.customizeIdTokenClaims(idClaims, client, request, sub, accessToken, account); | ||
|
||
IamUserInfo info = account.getUserInfo(); | ||
Set<String> groupNames = groupHelper.resolveGroupNames(info); | ||
|
||
if (!groupNames.isEmpty()) { | ||
idClaims.claim(KeycloakGroupHelper.KEYCLOAK_ROLES_CLAIM, groupNames); | ||
} | ||
|
||
// Drop group claims as set by IAM JWT profile | ||
idClaims.claim("groups", null); | ||
|
||
includeLabelsInIdToken(idClaims, account); | ||
|
||
} | ||
|
||
} |
61 changes: 61 additions & 0 deletions
61
...src/main/java/it/infn/mw/iam/core/oauth/profile/keycloak/KeycloakIntrospectionHelper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/** | ||
* Copyright (c) Istituto Nazionale di Fisica Nucleare (INFN). 2016-2021 | ||
* | ||
* 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 it.infn.mw.iam.core.oauth.profile.keycloak; | ||
|
||
import java.util.Map; | ||
import java.util.Set; | ||
|
||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity; | ||
import org.mitre.oauth2.service.IntrospectionResultAssembler; | ||
import org.mitre.openid.connect.model.UserInfo; | ||
|
||
import it.infn.mw.iam.config.IamProperties; | ||
import it.infn.mw.iam.core.oauth.profile.common.BaseIntrospectionHelper; | ||
import it.infn.mw.iam.core.oauth.scope.matchers.ScopeMatcherRegistry; | ||
import it.infn.mw.iam.persistence.repository.UserInfoAdapter; | ||
|
||
|
||
public class KeycloakIntrospectionHelper extends BaseIntrospectionHelper { | ||
|
||
private final KeycloakGroupHelper groupHelper; | ||
|
||
public KeycloakIntrospectionHelper(IamProperties props, IntrospectionResultAssembler assembler, | ||
ScopeMatcherRegistry registry, KeycloakGroupHelper helper) { | ||
super(props, assembler, registry); | ||
this.groupHelper = helper; | ||
} | ||
|
||
@Override | ||
public Map<String, Object> assembleIntrospectionResult(OAuth2AccessTokenEntity accessToken, | ||
UserInfo userInfo, Set<String> authScopes) { | ||
|
||
Map<String, Object> result = getAssembler().assembleFrom(accessToken, userInfo, authScopes); | ||
|
||
addIssuerClaim(result); | ||
addAudience(result, accessToken); | ||
addScopeClaim(result, filterScopes(accessToken, authScopes)); | ||
|
||
Set<String> groups = | ||
groupHelper.resolveGroupNames(((UserInfoAdapter) userInfo).getUserinfo()); | ||
|
||
if (!groups.isEmpty()) { | ||
result.put(KeycloakGroupHelper.KEYCLOAK_ROLES_CLAIM, groups); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
} |
41 changes: 41 additions & 0 deletions
41
...-service/src/main/java/it/infn/mw/iam/core/oauth/profile/keycloak/KeycloakJWTProfile.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/** | ||
* Copyright (c) Istituto Nazionale di Fisica Nucleare (INFN). 2016-2021 | ||
* | ||
* 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 it.infn.mw.iam.core.oauth.profile.keycloak; | ||
|
||
import it.infn.mw.iam.core.oauth.profile.IDTokenCustomizer; | ||
import it.infn.mw.iam.core.oauth.profile.IntrospectionResultHelper; | ||
import it.infn.mw.iam.core.oauth.profile.JWTAccessTokenBuilder; | ||
import it.infn.mw.iam.core.oauth.profile.UserInfoHelper; | ||
import it.infn.mw.iam.core.oauth.profile.iam.IamJWTProfile; | ||
|
||
public class KeycloakJWTProfile extends IamJWTProfile { | ||
|
||
public static final String PROFILE_VERSION = "1.0"; | ||
public static final String PROFILE_NAME = "Keycloak JWT profile " + PROFILE_VERSION; | ||
|
||
public KeycloakJWTProfile(JWTAccessTokenBuilder accessTokenBuilder, | ||
IDTokenCustomizer idTokenBuilder, UserInfoHelper userInfoHelper, | ||
IntrospectionResultHelper introspectionHelper) { | ||
|
||
super(accessTokenBuilder, idTokenBuilder, userInfoHelper, introspectionHelper); | ||
} | ||
|
||
@Override | ||
public String name() { | ||
return PROFILE_NAME; | ||
} | ||
|
||
} |
73 changes: 73 additions & 0 deletions
73
...in/java/it/infn/mw/iam/core/oauth/profile/keycloak/KeycloakProfileAccessTokenBuilder.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/** | ||
* Copyright (c) Istituto Nazionale di Fisica Nucleare (INFN). 2016-2021 | ||
* | ||
* 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 it.infn.mw.iam.core.oauth.profile.keycloak; | ||
|
||
import static java.util.Objects.isNull; | ||
import static java.util.stream.Collectors.joining; | ||
|
||
import java.time.Instant; | ||
import java.util.Date; | ||
import java.util.Set; | ||
|
||
import org.mitre.oauth2.model.OAuth2AccessTokenEntity; | ||
import org.mitre.openid.connect.model.UserInfo; | ||
import org.springframework.security.oauth2.provider.OAuth2Authentication; | ||
|
||
import com.nimbusds.jwt.JWTClaimsSet; | ||
import com.nimbusds.jwt.JWTClaimsSet.Builder; | ||
|
||
import it.infn.mw.iam.config.IamProperties; | ||
import it.infn.mw.iam.core.oauth.profile.common.BaseAccessTokenBuilder; | ||
import it.infn.mw.iam.persistence.repository.UserInfoAdapter; | ||
|
||
@SuppressWarnings("deprecation") | ||
public class KeycloakProfileAccessTokenBuilder extends BaseAccessTokenBuilder { | ||
|
||
public static final String PROFILE_VERSION = "1.0"; | ||
|
||
final KeycloakGroupHelper groupHelper; | ||
|
||
public KeycloakProfileAccessTokenBuilder(IamProperties properties, KeycloakGroupHelper groupHelper) { | ||
super(properties); | ||
this.groupHelper = groupHelper; | ||
} | ||
|
||
|
||
@Override | ||
public JWTClaimsSet buildAccessToken(OAuth2AccessTokenEntity token, | ||
OAuth2Authentication authentication, UserInfo userInfo, Instant issueTime) { | ||
|
||
Builder builder = baseJWTSetup(token, authentication, userInfo, issueTime); | ||
|
||
builder.notBeforeTime(Date.from(issueTime)); | ||
|
||
if (!token.getScope().isEmpty()) { | ||
builder.claim(SCOPE_CLAIM_NAME, token.getScope().stream().collect(joining(SPACE))); | ||
} | ||
|
||
if (!isNull(userInfo)) { | ||
Set<String> groupNames = | ||
groupHelper.resolveGroupNames(((UserInfoAdapter) userInfo).getUserinfo()); | ||
|
||
if (!groupNames.isEmpty()) { | ||
builder.claim(KeycloakGroupHelper.KEYCLOAK_ROLES_CLAIM, groupNames); | ||
} | ||
} | ||
|
||
return builder.build(); | ||
} | ||
|
||
} |
Oops, something went wrong.