From cf0ee31bc59d9d3695dcff28f2a5676ed0f4e00a Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Wed, 2 Aug 2017 19:42:35 -0400 Subject: [PATCH] KEYCLOAK-5249 --- .../broker/oidc/OIDCIdentityProvider.java | 95 +++++++------ .../social/gitlab/GitLabIdentityProvider.java | 109 +++++++++++++++ .../gitlab/GitLabIdentityProviderFactory.java | 47 +++++++ ...roker.social.SocialIdentityProviderFactory | 1 + .../messages/admin-messages_en.properties | 5 + .../realm-identity-provider-gitlab.html | 130 ++++++++++++++++++ 6 files changed, 344 insertions(+), 43 deletions(-) create mode 100755 services/src/main/java/org/keycloak/social/gitlab/GitLabIdentityProvider.java create mode 100755 services/src/main/java/org/keycloak/social/gitlab/GitLabIdentityProviderFactory.java create mode 100755 themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-gitlab.html diff --git a/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java b/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java index 45183c3658..a5304baac6 100755 --- a/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java +++ b/services/src/main/java/org/keycloak/broker/oidc/OIDCIdentityProvider.java @@ -75,7 +75,7 @@ public class OIDCIdentityProvider extends AbstractOAuth2IdentityProviderStian Thorgersen + */ +public class GitLabIdentityProvider extends OIDCIdentityProvider implements SocialIdentityProvider { + + public static final String AUTH_URL = "https://gitlab.com/oauth/authorize"; + public static final String TOKEN_URL = "https://gitlab.com/oauth/token"; + public static final String USER_INFO = "https://gitlab.com/api/v4/user"; + public static final String API_SCOPE = "api"; + + public GitLabIdentityProvider(KeycloakSession session, OIDCIdentityProviderConfig config) { + super(session, config); + config.setAuthorizationUrl(AUTH_URL); + config.setTokenUrl(TOKEN_URL); + config.setUserInfoUrl(USER_INFO); + + String defaultScope = config.getDefaultScope(); + + if (defaultScope.equals(SCOPE_OPENID)) { + config.setDefaultScope((API_SCOPE + " " + defaultScope).trim()); + } + } + + protected BrokeredIdentityContext extractIdentity(AccessTokenResponse tokenResponse, String accessToken, JsonWebToken idToken) throws IOException { + String id = idToken.getSubject(); + BrokeredIdentityContext identity = new BrokeredIdentityContext(id); + String name = (String)idToken.getOtherClaims().get(IDToken.NAME); + String preferredUsername = (String)idToken.getOtherClaims().get(IDToken.NICKNAME); + String email = (String)idToken.getOtherClaims().get(IDToken.EMAIL); + + if (getConfig().getDefaultScope().contains(API_SCOPE)) { + String userInfoUrl = getUserInfoUrl(); + if (userInfoUrl != null && !userInfoUrl.isEmpty() && (id == null || name == null || preferredUsername == null || email == null)) { + SimpleHttp request = JsonSimpleHttp.doGet(userInfoUrl, session) + .header("Authorization", "Bearer " + accessToken); + JsonNode userInfo = JsonSimpleHttp.asJson(request); + + name = getJsonProperty(userInfo, "name"); + preferredUsername = getJsonProperty(userInfo, "username"); + email = getJsonProperty(userInfo, "email"); + AbstractJsonUserAttributeMapper.storeUserProfileForMapper(identity, userInfo, getConfig().getAlias()); + } + } + identity.getContextData().put(FEDERATED_ACCESS_TOKEN_RESPONSE, tokenResponse); + identity.getContextData().put(VALIDATED_ID_TOKEN, idToken); + processAccessTokenResponse(identity, tokenResponse); + + identity.setId(id); + identity.setName(name); + identity.setEmail(email); + + identity.setBrokerUserId(getConfig().getAlias() + "." + id); + if (tokenResponse.getSessionState() != null) { + identity.setBrokerSessionId(getConfig().getAlias() + "." + tokenResponse.getSessionState()); + } + + if (preferredUsername == null) { + preferredUsername = email; + } + + if (preferredUsername == null) { + preferredUsername = id; + } + + identity.setUsername(preferredUsername); + return identity; + } + + + + +} diff --git a/services/src/main/java/org/keycloak/social/gitlab/GitLabIdentityProviderFactory.java b/services/src/main/java/org/keycloak/social/gitlab/GitLabIdentityProviderFactory.java new file mode 100755 index 0000000000..35e7a5e034 --- /dev/null +++ b/services/src/main/java/org/keycloak/social/gitlab/GitLabIdentityProviderFactory.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016 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.social.gitlab; + +import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig; +import org.keycloak.broker.oidc.OIDCIdentityProviderConfig; +import org.keycloak.broker.provider.AbstractIdentityProviderFactory; +import org.keycloak.broker.social.SocialIdentityProviderFactory; +import org.keycloak.models.IdentityProviderModel; +import org.keycloak.models.KeycloakSession; + +/** + * @author Pedro Igor + */ +public class GitLabIdentityProviderFactory extends AbstractIdentityProviderFactory implements SocialIdentityProviderFactory { + + public static final String PROVIDER_ID = "gitlab"; + + @Override + public String getName() { + return "GitLab"; + } + + @Override + public GitLabIdentityProvider create(KeycloakSession session, IdentityProviderModel model) { + return new GitLabIdentityProvider(session, new OIDCIdentityProviderConfig(model)); + } + + @Override + public String getId() { + return PROVIDER_ID; + } +} diff --git a/services/src/main/resources/META-INF/services/org.keycloak.broker.social.SocialIdentityProviderFactory b/services/src/main/resources/META-INF/services/org.keycloak.broker.social.SocialIdentityProviderFactory index 00a5e5163d..561970ad26 100755 --- a/services/src/main/resources/META-INF/services/org.keycloak.broker.social.SocialIdentityProviderFactory +++ b/services/src/main/resources/META-INF/services/org.keycloak.broker.social.SocialIdentityProviderFactory @@ -23,3 +23,4 @@ org.keycloak.social.stackoverflow.StackoverflowIdentityProviderFactory org.keycloak.social.twitter.TwitterIdentityProviderFactory org.keycloak.social.microsoft.MicrosoftIdentityProviderFactory org.keycloak.social.openshift.OpenshiftV3IdentityProviderFactory +org.keycloak.social.gitlab.GitLabIdentityProviderFactory diff --git a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties index 73412e983d..7a6ac2e810 100644 --- a/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties +++ b/themes/src/main/resources/theme/base/admin/messages/admin-messages_en.properties @@ -574,6 +574,11 @@ key=Key stackoverflow.key.tooltip=The Key obtained from Stack Overflow client registration. openshift.base-url=Base Url openshift.base-url.tooltip=Base Url to Openshift Online API +gitlab-application-id=Application Id +gitlab-application-secret=Application Secret +gitlab.application-id.tooltip=Application Id for the application you created in your GitLab Applications account menu +gitlab.application-secret.tooltip=Secret for the application that you created in your GitLab Applications account menu +gitlab.default-scopes.tooltip=Scopes to ask for on login. Will always ask for openid. Additionally adds api if you do not specify anything. # User federation sync-ldap-roles-to-keycloak=Sync LDAP Roles To Keycloak diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-gitlab.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-gitlab.html new file mode 100755 index 0000000000..152d1f1f40 --- /dev/null +++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-gitlab.html @@ -0,0 +1,130 @@ +
+ + + + +
+ + + +
+
+ +
+ +
+ {{:: 'redirect-uri.tooltip' | translate}} +
+
+
+
+ +
+ +
+ {{:: 'gitlab.application-id.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'gitlab.application-secret.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'gitlab.default-scopes.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'identity-provider.store-tokens.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'identity-provider.stored-tokens-readable.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'identity-provider.enabled.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'trust-email.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'link-only.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'hide-on-login-page.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'gui-order.tooltip' | translate}} +
+
+ +
+
+ +
+
+ {{:: 'first-broker-login-flow.tooltip' | translate}} +
+
+ +
+
+ +
+
+ {{:: 'post-broker-login-flow.tooltip' | translate}} +
+
+ +
+
+ + +
+
+
+
+ + \ No newline at end of file