From 4e23311318e75217eeffd5fd4ca0045a9db44acd Mon Sep 17 00:00:00 2001 From: Vlastimil Elias Date: Fri, 22 Jan 2016 11:03:08 +0100 Subject: [PATCH] KEYCLOAK-2348 - Social login provider for Microsoft account - KC master branch --- .../en/en-US/modules/identity-broker.xml | 95 ++++++++++++++++++- .../microsoft/MicrosoftIdentityProvider.java | 77 +++++++++++++++ .../MicrosoftIdentityProviderFactory.java | 46 +++++++++ .../MicrosoftUserAttributeMapper.java | 29 ++++++ ...oak.broker.provider.IdentityProviderMapper | 3 +- ...roker.social.SocialIdentityProviderFactory | 3 +- ...realm-identity-provider-microsoft-ext.html | 0 .../realm-identity-provider-microsoft.html | 1 + .../keycloak/login/resources/css/login.css | 11 +++ 9 files changed, 260 insertions(+), 5 deletions(-) create mode 100755 services/src/main/java/org/keycloak/social/microsoft/MicrosoftIdentityProvider.java create mode 100644 services/src/main/java/org/keycloak/social/microsoft/MicrosoftIdentityProviderFactory.java create mode 100644 services/src/main/java/org/keycloak/social/microsoft/MicrosoftUserAttributeMapper.java create mode 100755 themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-microsoft-ext.html create mode 100755 themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-microsoft.html diff --git a/docbook/auth-server-docs/reference/en/en-US/modules/identity-broker.xml b/docbook/auth-server-docs/reference/en/en-US/modules/identity-broker.xml index c0183ba3fd..8e32deced4 100755 --- a/docbook/auth-server-docs/reference/en/en-US/modules/identity-broker.xml +++ b/docbook/auth-server-docs/reference/en/en-US/modules/identity-broker.xml @@ -211,7 +211,7 @@ Social providers allows you to enable social authentication to your realm. Keycloak makes it easy to let users log in to your application using an existing account with a social network. - Currently Facebook, Google, Twitter, GitHub, LinkedIn and StackOverflow are supported with more planned for the future. + Currently Facebook, Google, Twitter, GitHub, LinkedIn, Microsoft and StackOverflow are supported with more planned for the future. @@ -357,7 +357,7 @@ So is trying to remember yet another username and password combination. Social identity providers makes it easy for users to register on your realm and quickly sign in using a social network. Keycloak provides built-in support for the most common social networks out there, such as Google, Facebook, Twitter, - Github, LinkedId and StackOverflow. + Github, LinkedId, Microsoft and StackOverflow.
@@ -855,6 +855,95 @@
+
+ Microsoft + + To enable login with Microsoft account you first have to register an OAuth application on + Microsoft account Developer Center. Then you need to copy the client id and secret into the Keycloak Admin Console. + + + Let's see first how to create an application with Microsoft. + + + + + Go to create new application on Microsoft account Developer Center url and login here. + Use any value for Application Name, Application Logo and URLs you want. + In API Settings set Target Domain to the domain where your Keycloak instance runs. + + + + + Copy Client Id and Client Secret from App Settings page. + + + + + Now that you have the client id and secret you can proceed with the creation of a Microsoft Identity Provider in Keycloak. As follows: + + + + + Select the Microsoft identity provider from the drop-down box on the top right corner of the identity providers table in Keycloak's Admin Console. You should be presented with a specific page to configure the selected provided. + + + + + Copy the client id and client secret to their corresponding fields in the Keycloak Admin Console. Click Save. + + + + + Once you create the identity provider in Keycloak, you must update your Microsoft application with the redirect url that was + generated to your identity provider. + + + + + Open the Microsoft account Developer Center and select API Settings of your application. In Redirect URLs + insert the redirect uri created by Keycloak. The redirect uri + usually have the following format: http://{host}:{port}/auth/realms/{realm}/broker/microsoft/endpoint. + + + + + + You can always get the redirect url for a specific identity provider from the table presented when you + click on the 'Identity Provider' tab in Realm > Settings. + + + + That is it! This pretty much what you need to do in order to setup this identity provider. + + + The table below lists some additional configuration options you may use when configuring this provider. + + + Configuration Options + + + + + Configuration + + + Description + + + + + + + Default Scopes + + + Allows you to manually specify the scopes that users must authorize when authenticating with this provider. For a complete list of scopes, please take a look at https://msdn.microsoft.com/en-us/library/hh243646.aspx. By default, Keycloak uses the following scopes: wl.basic,wl.emails + + + + +
+
StackOverflow @@ -1282,7 +1371,7 @@ keycloak.createLoginUrl({
Mapping/Importing User profile data from Social Identity Provider - You can import user profile data provided by social identity providers like Google, GitHub, LinkedIn, Stackoverflow and Facebook + You can import user profile data provided by social identity providers like Google, GitHub, LinkedIn, Microsoft, Stackoverflow and Facebook into new Keycloak user created from given social accounts. After you configure a broker, you'll see a Mappers button appear. Click on that and you'll get to the list of mappers that are assigned to this broker. There is a Create button on this page. Clicking on this create button allows you to create a broker mapper. diff --git a/services/src/main/java/org/keycloak/social/microsoft/MicrosoftIdentityProvider.java b/services/src/main/java/org/keycloak/social/microsoft/MicrosoftIdentityProvider.java new file mode 100755 index 0000000000..694c2f74dd --- /dev/null +++ b/services/src/main/java/org/keycloak/social/microsoft/MicrosoftIdentityProvider.java @@ -0,0 +1,77 @@ +package org.keycloak.social.microsoft; + +import java.net.URLEncoder; + +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.oidc.util.JsonSimpleHttp; +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 com.fasterxml.jackson.databind.JsonNode; + +/** + * + * Identity provider for Microsoft account. Uses OAuth 2 protocol of Windows Live Services as documented at https://msdn.microsoft.com/en-us/library/hh243647.aspx + * + * @author Vlastimil Elias (velias at redhat dot com) + */ +public class MicrosoftIdentityProvider extends AbstractOAuth2IdentityProvider implements SocialIdentityProvider { + + private static final Logger log = Logger.getLogger(MicrosoftIdentityProvider.class); + + public static final String AUTH_URL = "https://login.live.com/oauth20_authorize.srf"; + public static final String TOKEN_URL = "https://login.live.com/oauth20_token.srf"; + public static final String PROFILE_URL = "https://apis.live.net/v5.0/me"; + public static final String DEFAULT_SCOPE = "wl.basic,wl.emails"; + + public MicrosoftIdentityProvider(OAuth2IdentityProviderConfig config) { + super(config); + config.setAuthorizationUrl(AUTH_URL); + config.setTokenUrl(TOKEN_URL); + config.setUserInfoUrl(PROFILE_URL); + } + + @Override + protected BrokeredIdentityContext doGetFederatedIdentity(String accessToken) { + try { + String URL = PROFILE_URL + "?access_token=" + URLEncoder.encode(accessToken, "UTF-8"); + if (log.isDebugEnabled()) { + log.debug("Microsoft Live user profile request to: " + URL); + } + JsonNode profile = JsonSimpleHttp.asJson(SimpleHttp.doGet(URL)); + + String id = getJsonProperty(profile, "id"); + + String email = null; + if (profile.has("emails")) { + email = getJsonProperty(profile.get("emails"), "preferred"); + } + + BrokeredIdentityContext user = new BrokeredIdentityContext(id); + + user.setUsername(email != null ? email : id); + user.setFirstName(getJsonProperty(profile, "first_name")); + user.setLastName(getJsonProperty(profile, "last_name")); + if (email != null) + user.setEmail(email); + user.setIdpConfig(getConfig()); + user.setIdp(this); + + AbstractJsonUserAttributeMapper.storeUserProfileForMapper(user, profile, getConfig().getAlias()); + + return user; + } catch (Exception e) { + throw new IdentityBrokerException("Could not obtain user profile from Microsoft Live ID.", e); + } + } + + @Override + protected String getDefaultScopes() { + return DEFAULT_SCOPE; + } +} diff --git a/services/src/main/java/org/keycloak/social/microsoft/MicrosoftIdentityProviderFactory.java b/services/src/main/java/org/keycloak/social/microsoft/MicrosoftIdentityProviderFactory.java new file mode 100644 index 0000000000..e1105fa96a --- /dev/null +++ b/services/src/main/java/org/keycloak/social/microsoft/MicrosoftIdentityProviderFactory.java @@ -0,0 +1,46 @@ +/* + * JBoss, Home of Professional Open Source + * + * Copyright 2013 Red Hat, Inc. and/or its affiliates. + * + * 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.microsoft; + +import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig; +import org.keycloak.broker.provider.AbstractIdentityProviderFactory; +import org.keycloak.broker.social.SocialIdentityProviderFactory; +import org.keycloak.models.IdentityProviderModel; + +/** + * @author Vlastimil Elias (velias at redhat dot com) + */ +public class MicrosoftIdentityProviderFactory extends AbstractIdentityProviderFactory implements SocialIdentityProviderFactory { + + public static final String PROVIDER_ID = "microsoft"; + + @Override + public String getName() { + return "Microsoft"; + } + + @Override + public MicrosoftIdentityProvider create(IdentityProviderModel model) { + return new MicrosoftIdentityProvider(new OAuth2IdentityProviderConfig(model)); + } + + @Override + public String getId() { + return PROVIDER_ID; + } +} diff --git a/services/src/main/java/org/keycloak/social/microsoft/MicrosoftUserAttributeMapper.java b/services/src/main/java/org/keycloak/social/microsoft/MicrosoftUserAttributeMapper.java new file mode 100644 index 0000000000..bee8a91a71 --- /dev/null +++ b/services/src/main/java/org/keycloak/social/microsoft/MicrosoftUserAttributeMapper.java @@ -0,0 +1,29 @@ +/* + * JBoss, Home of Professional Open Source + * Copyright 2015 Red Hat Inc. and/or its affiliates and other contributors + * as indicated by the @authors tag. All rights reserved. + */ +package org.keycloak.social.microsoft; + +import org.keycloak.broker.oidc.mappers.AbstractJsonUserAttributeMapper; + +/** + * User attribute mapper. + * + * @author Vlastimil Elias (velias at redhat dot com) + */ +public class MicrosoftUserAttributeMapper extends AbstractJsonUserAttributeMapper { + + private static final String[] cp = new String[] { MicrosoftIdentityProviderFactory.PROVIDER_ID }; + + @Override + public String[] getCompatibleProviders() { + return cp; + } + + @Override + public String getId() { + return "microsoft-user-attribute-mapper"; + } + +} diff --git a/services/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper b/services/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper index 394c776cde..5f68100faa 100755 --- a/services/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper +++ b/services/src/main/resources/META-INF/services/org.keycloak.broker.provider.IdentityProviderMapper @@ -12,4 +12,5 @@ org.keycloak.social.facebook.FacebookUserAttributeMapper org.keycloak.social.github.GitHubUserAttributeMapper org.keycloak.social.google.GoogleUserAttributeMapper org.keycloak.social.linkedin.LinkedInUserAttributeMapper -org.keycloak.social.stackoverflow.StackoverflowUserAttributeMapper \ No newline at end of file +org.keycloak.social.stackoverflow.StackoverflowUserAttributeMapper +org.keycloak.social.microsoft.MicrosoftUserAttributeMapper 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 9ba5b4d1af..ddb6876238 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 @@ -3,4 +3,5 @@ org.keycloak.social.github.GitHubIdentityProviderFactory org.keycloak.social.google.GoogleIdentityProviderFactory org.keycloak.social.linkedin.LinkedInIdentityProviderFactory org.keycloak.social.stackoverflow.StackoverflowIdentityProviderFactory -org.keycloak.social.twitter.TwitterIdentityProviderFactory \ No newline at end of file +org.keycloak.social.twitter.TwitterIdentityProviderFactory +org.keycloak.social.microsoft.MicrosoftIdentityProviderFactory diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-microsoft-ext.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-microsoft-ext.html new file mode 100755 index 0000000000..e69de29bb2 diff --git a/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-microsoft.html b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-microsoft.html new file mode 100755 index 0000000000..a4630ac786 --- /dev/null +++ b/themes/src/main/resources/theme/base/admin/resources/partials/realm-identity-provider-microsoft.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/themes/src/main/resources/theme/keycloak/login/resources/css/login.css b/themes/src/main/resources/theme/keycloak/login/resources/css/login.css index b45f9b9073..9c28f3afdb 100644 --- a/themes/src/main/resources/theme/keycloak/login/resources/css/login.css +++ b/themes/src/main/resources/theme/keycloak/login/resources/css/login.css @@ -201,6 +201,9 @@ ol#kc-totp-settings li:first-of-type { .zocial.facebook, .zocial.github, .zocial.google, +.zocial.microsoft, +.zocial.stackoverflow, +.zocial.linkedin, .zocial.twitter { background-image: none; border-radius: 2px; @@ -222,10 +225,18 @@ ol#kc-totp-settings li:first-of-type { .zocial.facebook:hover, .zocial.github:hover, .zocial.google:hover, +.zocial.microsoft:hover, +.zocial.stackoverflow:hover, +.zocial.linkedin:hover, .zocial.twitter:hover { background-image: linear-gradient(rgba(0, 0, 0, 0.2) 0%, rgba(0, 0, 0, 0.2) 100%) !important; } +/* Copy of zocial windows classes to be used for microsoft's social provider button */ +.zocial.microsoft {background-color: #0052a4; color: #fff;} +.zocial.microsoft:before { content: "\f15d"; } + + @media (min-width: 768px) { #kc-container-wrapper { bottom: 13%;