From 4dfb74b5a850752e364789333d6dd7ac68df923a Mon Sep 17 00:00:00 2001 From: Hiroyuki Wada Date: Thu, 1 Nov 2018 18:55:56 +0900 Subject: [PATCH] Prototype --- .gitignore | 4 + ear/pom.xml | 47 +++++++ .../META-INF/jboss-deployment-structure.xml | 15 +++ ejb/pom.xml | 52 +++++++ .../discord/DiscordIdentityProvider.java | 95 +++++++++++++ .../DiscordIdentityProviderFactory.java | 46 +++++++ .../resources/META-INF/keycloak-themes.json | 6 + ...roker.social.SocialIdentityProviderFactory | 1 + .../realm-identity-provider-discord.html | 127 ++++++++++++++++++ .../theme/discord/admin/theme.properties | 2 + pom.xml | 67 +++++++++ 11 files changed, 462 insertions(+) create mode 100644 .gitignore create mode 100755 ear/pom.xml create mode 100755 ear/src/main/application/META-INF/jboss-deployment-structure.xml create mode 100755 ejb/pom.xml create mode 100755 ejb/src/main/java/org/keycloak/social/discord/DiscordIdentityProvider.java create mode 100755 ejb/src/main/java/org/keycloak/social/discord/DiscordIdentityProviderFactory.java create mode 100644 ejb/src/main/resources/META-INF/keycloak-themes.json create mode 100755 ejb/src/main/resources/META-INF/services/org.keycloak.broker.social.SocialIdentityProviderFactory create mode 100755 ejb/src/main/resources/theme/discord/admin/resources/partials/realm-identity-provider-discord.html create mode 100644 ejb/src/main/resources/theme/discord/admin/theme.properties create mode 100755 pom.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d163d47 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +target +.project +.classpath +.settings diff --git a/ear/pom.xml b/ear/pom.xml new file mode 100755 index 0000000..e544cb1 --- /dev/null +++ b/ear/pom.xml @@ -0,0 +1,47 @@ + + + org.keycloak.extensions + keycloak-discord-parent + 1.0.0-SNAPSHOT + + + Keycloak Discord EAR + + 4.0.0 + + keycloak-discord-ear + ear + + + + org.keycloak.extensions + keycloak-discord-ejb + ejb + + + + + keycloak-discord + + + + org.apache.maven.plugins + maven-ear-plugin + 2.10 + + 7 + lib + no-version + + + + org.wildfly.plugins + wildfly-maven-plugin + + false + + + + + diff --git a/ear/src/main/application/META-INF/jboss-deployment-structure.xml b/ear/src/main/application/META-INF/jboss-deployment-structure.xml new file mode 100755 index 0000000..6d7e67c --- /dev/null +++ b/ear/src/main/application/META-INF/jboss-deployment-structure.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/ejb/pom.xml b/ejb/pom.xml new file mode 100755 index 0000000..67706f1 --- /dev/null +++ b/ejb/pom.xml @@ -0,0 +1,52 @@ + + + org.keycloak.extensions + keycloak-discord-parent + 1.0.0-SNAPSHOT + + + Keycloak Discord EJB + + 4.0.0 + + keycloak-discord-ejb + jar + + + + org.keycloak + keycloak-core + provided + + + org.keycloak + keycloak-server-spi + provided + + + org.keycloak + keycloak-server-spi-private + provided + + + org.keycloak + keycloak-services + provided + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.8 + 1.8 + + + + + diff --git a/ejb/src/main/java/org/keycloak/social/discord/DiscordIdentityProvider.java b/ejb/src/main/java/org/keycloak/social/discord/DiscordIdentityProvider.java new file mode 100755 index 0000000..ec92293 --- /dev/null +++ b/ejb/src/main/java/org/keycloak/social/discord/DiscordIdentityProvider.java @@ -0,0 +1,95 @@ +/* + * Copyright 2018 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.discord; + +import org.jboss.logging.Logger; +import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider; +import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig; +import org.keycloak.broker.oidc.mappers.AbstractJsonUserAttributeMapper; +import org.keycloak.broker.provider.BrokeredIdentityContext; +import org.keycloak.broker.provider.IdentityBrokerException; +import org.keycloak.broker.provider.util.SimpleHttp; +import org.keycloak.broker.social.SocialIdentityProvider; +import org.keycloak.events.EventBuilder; +import org.keycloak.models.KeycloakSession; +import org.keycloak.social.linkedin.LinkedInIdentityProvider; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * @author Hiroyuki Wada + */ +public class DiscordIdentityProvider extends AbstractOAuth2IdentityProvider + implements SocialIdentityProvider { + + private static final Logger log = Logger.getLogger(LinkedInIdentityProvider.class); + + public static final String AUTH_URL = "https://discordapp.com/api/oauth2/authorize"; + public static final String TOKEN_URL = "https://discordapp.com/api/oauth2/token"; + public static final String PROFILE_URL = "https://discordapp.com/api/users/@me"; + public static final String DEFAULT_SCOPE = "identify email"; + + public DiscordIdentityProvider(KeycloakSession session, OAuth2IdentityProviderConfig config) { + super(session, config); + config.setAuthorizationUrl(AUTH_URL); + config.setTokenUrl(TOKEN_URL); + config.setUserInfoUrl(PROFILE_URL); + } + + @Override + protected boolean supportsExternalExchange() { + return true; + } + + @Override + protected String getProfileEndpointForValidation(EventBuilder event) { + return PROFILE_URL; + } + + @Override + protected BrokeredIdentityContext extractIdentityFromProfile(EventBuilder event, JsonNode profile) { + BrokeredIdentityContext user = new BrokeredIdentityContext(getJsonProperty(profile, "id")); + + user.setUsername(getJsonProperty(profile, "username")); +// user.setName(getJsonProperty(profile, "username")); + user.setEmail(getJsonProperty(profile, "email")); + user.setIdpConfig(getConfig()); + user.setIdp(this); + + AbstractJsonUserAttributeMapper.storeUserProfileForMapper(user, profile, getConfig().getAlias()); + + return user; + } + + @Override + protected BrokeredIdentityContext doGetFederatedIdentity(String accessToken) { + log.debug("doGetFederatedIdentity()"); + try { + JsonNode profile = SimpleHttp.doGet(PROFILE_URL, session).header("Authorization", "Bearer " + accessToken).asJson(); +// System.out.println(profile.toString()); + return extractIdentityFromProfile(null, profile); + } catch (Exception e) { + throw new IdentityBrokerException("Could not obtain user profile from discord.", e); + } + } + + @Override + protected String getDefaultScopes() { + return DEFAULT_SCOPE; + } +} \ No newline at end of file diff --git a/ejb/src/main/java/org/keycloak/social/discord/DiscordIdentityProviderFactory.java b/ejb/src/main/java/org/keycloak/social/discord/DiscordIdentityProviderFactory.java new file mode 100755 index 0000000..4e1732c --- /dev/null +++ b/ejb/src/main/java/org/keycloak/social/discord/DiscordIdentityProviderFactory.java @@ -0,0 +1,46 @@ +/* + * Copyright 2018 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.discord; + +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 Hiroyuki Wada + */ +public class DiscordIdentityProviderFactory extends AbstractIdentityProviderFactory implements SocialIdentityProviderFactory { + + public static final String PROVIDER_ID = "discord"; + + @Override + public String getName() { + return "Discord"; + } + + @Override + public DiscordIdentityProvider create(KeycloakSession session, IdentityProviderModel model) { + return new DiscordIdentityProvider(session, new OIDCIdentityProviderConfig(model)); + } + + @Override + public String getId() { + return PROVIDER_ID; + } +} \ No newline at end of file diff --git a/ejb/src/main/resources/META-INF/keycloak-themes.json b/ejb/src/main/resources/META-INF/keycloak-themes.json new file mode 100644 index 0000000..c1f3185 --- /dev/null +++ b/ejb/src/main/resources/META-INF/keycloak-themes.json @@ -0,0 +1,6 @@ +{ + "themes": [{ + "name" : "discord", + "types": [ "admin" ] + }] +} diff --git a/ejb/src/main/resources/META-INF/services/org.keycloak.broker.social.SocialIdentityProviderFactory b/ejb/src/main/resources/META-INF/services/org.keycloak.broker.social.SocialIdentityProviderFactory new file mode 100755 index 0000000..34b9b4a --- /dev/null +++ b/ejb/src/main/resources/META-INF/services/org.keycloak.broker.social.SocialIdentityProviderFactory @@ -0,0 +1 @@ +org.keycloak.social.discord.DiscordIdentityProviderFactory \ No newline at end of file diff --git a/ejb/src/main/resources/theme/discord/admin/resources/partials/realm-identity-provider-discord.html b/ejb/src/main/resources/theme/discord/admin/resources/partials/realm-identity-provider-discord.html new file mode 100755 index 0000000..92fabe3 --- /dev/null +++ b/ejb/src/main/resources/theme/discord/admin/resources/partials/realm-identity-provider-discord.html @@ -0,0 +1,127 @@ +
+ + + + +
+
+
+ +
+ +
+ {{:: 'redirect-uri.tooltip' | translate}} +
+
+
+
+ +
+ +
+ {{:: 'discord.client-id.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'discord.client-secret.tooltip' | translate}} +
+
+ +
+ +
+ {{:: 'discord.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}} +
+
+ +
+
+ + +
+
+
+
+ + diff --git a/ejb/src/main/resources/theme/discord/admin/theme.properties b/ejb/src/main/resources/theme/discord/admin/theme.properties new file mode 100644 index 0000000..93d3b28 --- /dev/null +++ b/ejb/src/main/resources/theme/discord/admin/theme.properties @@ -0,0 +1,2 @@ +parent=keycloak + diff --git a/pom.xml b/pom.xml new file mode 100755 index 0000000..dd522eb --- /dev/null +++ b/pom.xml @@ -0,0 +1,67 @@ + + + Keycloak Discord + + 4.0.0 + + org.keycloak.extensions + keycloak-discord-parent + 1.0.0-SNAPSHOT + pom + + + 4.5.0.Final + 1.1.0.Final + + + + + + org.keycloak.bom + keycloak-spi-bom + ${version.keycloak} + pom + import + + + org.keycloak.extensions + keycloak-discord-ejb + ${project.version} + ejb + + + org.keycloak + keycloak-server-spi-private + provided + ${version.keycloak} + + + org.keycloak + keycloak-services + provided + ${version.keycloak} + + + + + + ejb + ear + + + + + + + org.wildfly.plugins + wildfly-maven-plugin + ${version.wildfly.maven.plugin} + + true + + + + + +