Merge pull request #2090 from velias/KEYCLOAK-2348

KEYCLOAK-2348 - Social login provider for Microsoft account - KC master branch
This commit is contained in:
Stian Thorgersen 2016-01-22 13:26:45 +01:00
commit e71ac6f1b3
9 changed files with 260 additions and 5 deletions

View file

@ -211,7 +211,7 @@
<para>
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.
</para>
</listitem>
</varlistentry>
@ -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.
</para>
<section>
@ -855,6 +855,95 @@
</tgroup>
</table>
</section>
<section>
<title>Microsoft</title>
<para>
To enable login with Microsoft account you first have to register an OAuth application on
<ulink url="https://account.live.com/developers/applications/index">Microsoft account Developer Center</ulink>. Then you need to copy the client id and secret into the Keycloak Admin Console.
</para>
<para>
Let's see first how to create an application with Microsoft.
</para>
<orderedlist>
<listitem>
<para>
Go to <ulink url="https://account.live.com/developers/applications/create">create new application on Microsoft account Developer Center</ulink> url and login here.
Use any value for <literal>Application Name</literal>, <literal>Application Logo</literal> and <literal>URLs</literal> you want.
In <literal>API Settings</literal> set <literal>Target Domain</literal> to the domain where your Keycloak instance runs.
</para>
</listitem>
<listitem>
<para>
Copy <literal>Client Id</literal> and <literal>Client Secret</literal> from <literal>App Settings</literal> page.
</para>
</listitem>
</orderedlist>
<para>
Now that you have the client id and secret you can proceed with the creation of a Microsoft Identity Provider in Keycloak. As follows:
</para>
<orderedlist>
<listitem>
<para>
Select the <literal>Microsoft</literal> 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.
</para>
</listitem>
<listitem>
<para>
Copy the client id and client secret to their corresponding fields in the Keycloak Admin Console. Click <literal>Save</literal>.
</para>
</listitem>
</orderedlist>
<para>
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.
</para>
<orderedlist>
<listitem>
<para>
Open the Microsoft account Developer Center and select <literal>API Settings</literal> of your application. In <literal>Redirect URLs</literal>
insert the redirect uri created by Keycloak. The redirect uri
usually have the following format: <literal>http://{host}:{port}/auth/realms/{realm}/broker/microsoft/endpoint</literal>.
</para>
</listitem>
</orderedlist>
<note>
<para>
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 <emphasis>Realm > Settings</emphasis>.
</para>
</note>
<para>
That is it! This pretty much what you need to do in order to setup this identity provider.
</para>
<para>
The table below lists some additional configuration options you may use when configuring this provider.
</para>
<table>
<title>Configuration Options</title>
<tgroup align="left" cols="2">
<thead>
<row>
<entry>
Configuration
</entry>
<entry>
Description
</entry>
</row>
</thead>
<tbody valign="top">
<row>
<entry>
<literal>Default Scopes</literal>
</entry>
<entry>
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 <ulink url="https://msdn.microsoft.com/en-us/library/hh243646.aspx">https://msdn.microsoft.com/en-us/library/hh243646.aspx</ulink>. By default, Keycloak uses the following scopes: <literal>wl.basic,wl.emails</literal>
</entry>
</row>
</tbody>
</tgroup>
</table>
</section>
<section>
<title>StackOverflow</title>
<para>
@ -1282,7 +1371,7 @@ keycloak.createLoginUrl({
<section>
<title>Mapping/Importing User profile data from Social Identity Provider</title>
<para>
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 <literal>Mappers</literal>
button appear. Click on that and you'll get to the list of mappers that are assigned to this broker. There is a
<literal>Create</literal> button on this page. Clicking on this create button allows you to create a broker mapper.

View file

@ -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 <a href="https://msdn.microsoft.com/en-us/library/hh243647.aspx">https://msdn.microsoft.com/en-us/library/hh243647.aspx</a>
*
* @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;
}
}

View file

@ -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<MicrosoftIdentityProvider> implements SocialIdentityProviderFactory<MicrosoftIdentityProvider> {
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;
}
}

View file

@ -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";
}
}

View file

@ -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
org.keycloak.social.stackoverflow.StackoverflowUserAttributeMapper
org.keycloak.social.microsoft.MicrosoftUserAttributeMapper

View file

@ -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
org.keycloak.social.twitter.TwitterIdentityProviderFactory
org.keycloak.social.microsoft.MicrosoftIdentityProviderFactory

View file

@ -0,0 +1 @@
<div data-ng-include data-src="resourceUrl + '/partials/realm-identity-provider-social.html'"></div>

View file

@ -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%;