keycloak-aplcache

Merge pull request #1076 from velias/KEYCLOAK-28 KEYCLOAK-28

3/23/2015 7:30:21 AM

Details

diff --git a/dependencies/server-all/pom.xml b/dependencies/server-all/pom.xml
index fe6d5cc..a7bd522 100755
--- a/dependencies/server-all/pom.xml
+++ b/dependencies/server-all/pom.xml
@@ -122,6 +122,11 @@
             <artifactId>keycloak-social-facebook</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-social-linkedin</artifactId>
+            <version>${project.version}</version>
+        </dependency>
 
         <!-- ldap federation api -->
         <dependency>
diff --git a/distribution/modules/build.xml b/distribution/modules/build.xml
index 9199165..ad0f9e7 100755
--- a/distribution/modules/build.xml
+++ b/distribution/modules/build.xml
@@ -235,6 +235,10 @@
         <module-def name="org.keycloak.keycloak-social-facebook">
             <maven-resource group="org.keycloak" artifact="keycloak-social-facebook"/>
         </module-def>
+    	
+    	  <module-def name="org.keycloak.keycloak-social-linkedin">
+    	      <maven-resource group="org.keycloak" artifact="keycloak-social-linkedin"/>
+    	  </module-def>
 
         <module-def name="org.keycloak.keycloak-kerberos-federation">
             <maven-resource group="org.keycloak" artifact="keycloak-kerberos-federation"/>
diff --git a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-server/main/module.xml b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-server/main/module.xml
index c757599..f8a251d 100755
--- a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-server/main/module.xml
+++ b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-server/main/module.xml
@@ -57,6 +57,7 @@
         <module name="org.keycloak.keycloak-social-github" services="import"/>
         <module name="org.keycloak.keycloak-social-google" services="import"/>
         <module name="org.keycloak.keycloak-social-twitter" services="import"/>
+        <module name="org.keycloak.keycloak-social-linkedin" services="import"/>
         <module name="org.keycloak.keycloak-subsystem" services="import"/>
         <module name="org.keycloak.keycloak-timer-api" services="import"/>
         <module name="org.keycloak.keycloak-timer-basic" services="import"/>
diff --git a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-services/main/module.xml b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-services/main/module.xml
index bafc53f..6166b9b 100755
--- a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-services/main/module.xml
+++ b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-services/main/module.xml
@@ -60,6 +60,7 @@
         <module name="org.keycloak.keycloak-social-github" services="import"/>
         <module name="org.keycloak.keycloak-social-google" services="import"/>
         <module name="org.keycloak.keycloak-social-twitter" services="import"/>
+        <module name="org.keycloak.keycloak-social-linkedin" services="import"/>
         <module name="org.keycloak.keycloak-timer-api" services="import"/>
         <module name="org.keycloak.keycloak-timer-basic" services="import"/>
 
diff --git a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-social-linkedin/main/module.xml b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-social-linkedin/main/module.xml
new file mode 100755
index 0000000..00853bf
--- /dev/null
+++ b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-social-linkedin/main/module.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-social-linkedin">
+    <resources>
+        <!-- Insert resources here -->
+    </resources>
+    <dependencies>
+        <module name="org.keycloak.keycloak-core"/>
+        <module name="org.keycloak.keycloak-social-core"/>
+        <module name="org.keycloak.keycloak-broker-core"/>
+        <module name="org.keycloak.keycloak-broker-oidc"/>
+        <module name="org.keycloak.keycloak-model-api"/>
+        <module name="org.jboss.logging"/>
+        <module name="javax.api"/>
+        <module name="org.codehaus.jackson.jackson-core-asl"/>
+        <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+        <module name="org.codehaus.jackson.jackson-xc"/>
+    </dependencies>
+
+</module>
diff --git a/distribution/subsystem-war/src/main/webapp/WEB-INF/jboss-deployment-structure.xml b/distribution/subsystem-war/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
index 29de32e..6a97ca5 100755
--- a/distribution/subsystem-war/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
+++ b/distribution/subsystem-war/src/main/webapp/WEB-INF/jboss-deployment-structure.xml
@@ -50,6 +50,7 @@
             <module name="org.keycloak.keycloak-social-github" services="import"/>
             <module name="org.keycloak.keycloak-social-google" services="import"/>
             <module name="org.keycloak.keycloak-social-twitter" services="import"/>
+            <module name="org.keycloak.keycloak-social-linkedin" services="import"/>
             <module name="org.keycloak.keycloak-timer-api" services="import"/>
             <module name="org.keycloak.keycloak-timer-basic" services="import"/>
             <module name="org.hibernate" services="import"/>
diff --git a/docbook/reference/en/en-US/modules/identity-broker.xml b/docbook/reference/en/en-US/modules/identity-broker.xml
index 0ab53f0..3a74b73 100755
--- a/docbook/reference/en/en-US/modules/identity-broker.xml
+++ b/docbook/reference/en/en-US/modules/identity-broker.xml
@@ -715,6 +715,99 @@
                 </tgroup>
             </table>
         </section>
+        <section>
+            <title>LinkedIn</title>
+            <para>
+                To enable login with LinkedIn you first have to create an application in
+                <ulink url="https://www.linkedin.com/secure/developer">LinkedIn Developer Network</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 LinkedIn.
+            </para>
+            <orderedlist>
+                <listitem>
+                    <para>
+                        Log in to <ulink url="https://www.linkedin.com/secure/developer">LinkedIn Developer Network</ulink>. Click the
+                        <literal>Add New Application</literal> link. Use any value for <literal>Application Name</literal>,
+                        <literal>Website URL</literal>, <literal>Description</literal>, <literal>Developer Contact Email</literal> and <literal>Phone</literal> you want.
+                        Select <literal>r_basicprofile</literal> and <literal>r_emailaddress</literal> in the <literal>Default Scope</literal> section. 
+                        Click the <literal>Add Application</literal> button.
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        Copy <literal>Consumer Key / API Key</literal> and <literal>Consumer Secret / Secret Key</literal> from the shown page.
+                    </para>
+                </listitem>
+            </orderedlist>
+            <para>
+                Now that you have the client id and secret, you can proceed with the creation of a LinkedIn Identity Provider in Keycloak. As follows:
+            </para>
+            <orderedlist>
+                <listitem>
+                    <para>
+                        Select the <literal>LinkedIn</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 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 LinkedIn application with the redirect url that was
+                generated to your identity provider.
+            </para>
+            <orderedlist>
+                <listitem>
+                    <para>
+                        Open the LinkedIn Developer Network and select your application. In <literal>OAuth 2.0 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/{provider_alias}/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 application configuration in <ulink url="https://www.linkedin.com/secure/developer">LinkedIn Developer Network</ulink>. By default, Keycloak uses the following scopes: <literal>r_basicprofile r_emailaddress</literal>
+                            </entry>
+                        </row>
+                    </tbody>
+                </tgroup>
+            </table>
+        </section>        
     </section>
 
     <section>
diff --git a/examples/cors/angular-product-app/.gitignore b/examples/cors/angular-product-app/.gitignore
new file mode 100644
index 0000000..9500957
--- /dev/null
+++ b/examples/cors/angular-product-app/.gitignore
@@ -0,0 +1 @@
+/.externalToolBuilders/*
diff --git a/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-linkedin.html b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-linkedin.html
new file mode 100755
index 0000000..a4630ac
--- /dev/null
+++ b/forms/common-themes/src/main/resources/theme/admin/base/resources/partials/realm-identity-provider-linkedin.html
@@ -0,0 +1 @@
+<div data-ng-include data-src="resourceUrl + '/partials/realm-identity-provider-social.html'"></div>
\ No newline at end of file

README.md 2(+1 -1)

diff --git a/README.md b/README.md
index 3ba55db..1d05652 100755
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@ It can be used for social applications as well as enterprise applications.  It i
 Here's some of the features:
 
 * SSO and Single Log Out for browser applications
-* Social Broker.  Enable Google, Facebook, Yahoo, Twitter social login with no code required.
+* Social Broker.  Enable Google, Facebook, Yahoo, Twitter, GitHub, LinkedIn social login with no code required.
 * Optional LDAP/Active Directory integration
 * Optional User Registration
 * Password and TOTP support (via Google Authenticator or FreeOTP).  Client cert auth coming soon.
diff --git a/social/linkedin/.gitignore b/social/linkedin/.gitignore
new file mode 100644
index 0000000..b83d222
--- /dev/null
+++ b/social/linkedin/.gitignore
@@ -0,0 +1 @@
+/target/
diff --git a/social/linkedin/pom.xml b/social/linkedin/pom.xml
new file mode 100755
index 0000000..d9fd603
--- /dev/null
+++ b/social/linkedin/pom.xml
@@ -0,0 +1,40 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>keycloak-social-parent</artifactId>
+        <groupId>org.keycloak</groupId>
+        <version>1.2.0.Beta1-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging>
+
+    <artifactId>keycloak-social-linkedin</artifactId>
+    <name>Keycloak Social LinkedIn</name>
+    <description/>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-social-core</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.keycloak</groupId>
+            <artifactId>keycloak-broker-oidc</artifactId>
+            <version>${project.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.codehaus.jackson</groupId>
+            <artifactId>jackson-mapper-asl</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.jboss.logging</groupId>
+            <artifactId>jboss-logging</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java b/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java
new file mode 100755
index 0000000..298612e
--- /dev/null
+++ b/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProvider.java
@@ -0,0 +1,109 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 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.linkedin;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLDecoder;
+
+import org.codehaus.jackson.JsonNode;
+import org.jboss.logging.Logger;
+import org.keycloak.broker.oidc.AbstractOAuth2IdentityProvider;
+import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig;
+import org.keycloak.broker.oidc.util.SimpleHttp;
+import org.keycloak.broker.provider.FederatedIdentity;
+import org.keycloak.broker.provider.IdentityBrokerException;
+import org.keycloak.social.SocialIdentityProvider;
+
+/**
+ * LinkedIn social provider. See https://developer.linkedin.com/docs/oauth2
+ * 
+ * @author Vlastimil Elias (velias at redhat dot com)
+ */
+public class LinkedInIdentityProvider extends AbstractOAuth2IdentityProvider implements SocialIdentityProvider {
+
+	private static final Logger log = Logger.getLogger(LinkedInIdentityProvider.class);
+
+	public static final String AUTH_URL = "https://www.linkedin.com/uas/oauth2/authorization";
+	public static final String TOKEN_URL = "https://www.linkedin.com/uas/oauth2/accessToken";
+	public static final String PROFILE_URL = "https://api.linkedin.com/v1/people/~:(id,formatted-name,email-address,public-profile-url)?format=json";
+	public static final String DEFAULT_SCOPE = "r_basicprofile r_emailaddress";
+
+	public LinkedInIdentityProvider(OAuth2IdentityProviderConfig config) {
+		super(config);
+		config.setAuthorizationUrl(AUTH_URL);
+		config.setTokenUrl(TOKEN_URL);
+		config.setUserInfoUrl(PROFILE_URL);
+	}
+
+	@Override
+	protected FederatedIdentity doGetFederatedIdentity(String accessToken) {
+		log.debug("doGetFederatedIdentity()");
+		try {
+			JsonNode profile = SimpleHttp.doGet(PROFILE_URL).header("Authorization", "Bearer " + accessToken).asJson();
+
+			FederatedIdentity user = new FederatedIdentity(getJsonProperty(profile, "id"));
+
+			user.setUsername(extractUsernameFromProfileURL(getJsonProperty(profile, "publicProfileUrl")));
+			user.setName(getJsonProperty(profile, "formattedName"));
+			user.setEmail(getJsonProperty(profile, "emailAddress"));
+
+			return user;
+		} catch (Exception e) {
+			throw new IdentityBrokerException("Could not obtain user profile from github.", e);
+		}
+	}
+
+	protected static String extractUsernameFromProfileURL(String profileURL) {
+		if (isNotBlank(profileURL)) {
+
+			try {
+				log.debug("go to extract username from profile URL " + profileURL);
+				URL u = new URL(profileURL);
+				String path = u.getPath();
+				if (isNotBlank(path) && path.length() > 1) {
+					if (path.startsWith("/")) {
+						path = path.substring(1);
+					}
+					String[] pe = path.split("/");
+					if (pe.length >= 2) {
+						return URLDecoder.decode(pe[1], "UTF-8");
+					} else {
+						log.warn("LinkedIn profile URL path is without second part: " + profileURL);
+					}
+				} else {
+					log.warn("LinkedIn profile URL is without path part: " + profileURL);
+				}
+			} catch (MalformedURLException e) {
+				log.warn("LinkedIn profile URL is malformed: " + profileURL);
+			} catch (Exception e) {
+				log.warn("LinkedIn profile URL " + profileURL + " username extraction failed due: " + e.getMessage());
+			}
+		}
+		return null;
+	}
+
+	private static boolean isNotBlank(String s) {
+		return s != null && s.trim().length() > 0;
+	}
+
+	@Override
+	protected String getDefaultScopes() {
+		return DEFAULT_SCOPE;
+	}
+}
diff --git a/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProviderFactory.java b/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProviderFactory.java
new file mode 100644
index 0000000..958a513
--- /dev/null
+++ b/social/linkedin/src/main/java/org/keycloak/social/linkedin/LinkedInIdentityProviderFactory.java
@@ -0,0 +1,47 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Copyright 2015 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.linkedin;
+
+import org.keycloak.broker.oidc.OAuth2IdentityProviderConfig;
+import org.keycloak.broker.provider.AbstractIdentityProviderFactory;
+import org.keycloak.models.IdentityProviderModel;
+import org.keycloak.social.SocialIdentityProviderFactory;
+
+/**
+ * @author Vlastimil Elias (velias at redhat dot com)
+ */
+public class LinkedInIdentityProviderFactory extends AbstractIdentityProviderFactory<LinkedInIdentityProvider>
+		implements SocialIdentityProviderFactory<LinkedInIdentityProvider> {
+
+	public static final String PROVIDER_ID = "linkedin";
+
+	@Override
+	public String getName() {
+		return "LinkedIn";
+	}
+
+	@Override
+	public LinkedInIdentityProvider create(IdentityProviderModel model) {
+		return new LinkedInIdentityProvider(new OAuth2IdentityProviderConfig(model));
+	}
+
+	@Override
+	public String getId() {
+		return PROVIDER_ID;
+	}
+}
diff --git a/social/linkedin/src/main/resources/META-INF/services/org.keycloak.social.SocialIdentityProviderFactory b/social/linkedin/src/main/resources/META-INF/services/org.keycloak.social.SocialIdentityProviderFactory
new file mode 100644
index 0000000..5ffef97
--- /dev/null
+++ b/social/linkedin/src/main/resources/META-INF/services/org.keycloak.social.SocialIdentityProviderFactory
@@ -0,0 +1 @@
+org.keycloak.social.linkedin.LinkedInIdentityProviderFactory
\ No newline at end of file

social/pom.xml 1(+1 -0)

diff --git a/social/pom.xml b/social/pom.xml
index 386a215..ded7c60 100755
--- a/social/pom.xml
+++ b/social/pom.xml
@@ -20,6 +20,7 @@
         <module>google</module>
         <module>twitter</module>
         <module>facebook</module>
+        <module>linkedin</module>
     </modules>
 
 </project>
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderModelTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderModelTest.java
index 2dd3164..84bbc9c 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderModelTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/AbstractIdentityProviderModelTest.java
@@ -24,6 +24,7 @@ import org.keycloak.social.facebook.FacebookIdentityProviderFactory;
 import org.keycloak.social.github.GitHubIdentityProviderFactory;
 import org.keycloak.social.google.GoogleIdentityProviderFactory;
 import org.keycloak.social.twitter.TwitterIdentityProviderFactory;
+import org.keycloak.social.linkedin.LinkedInIdentityProviderFactory;
 import org.keycloak.testsuite.model.AbstractModelTest;
 
 import java.util.Collections;
@@ -47,6 +48,7 @@ public abstract class AbstractIdentityProviderModelTest extends AbstractModelTes
         this.expectedProviders.add(FacebookIdentityProviderFactory.PROVIDER_ID);
         this.expectedProviders.add(GitHubIdentityProviderFactory.PROVIDER_ID);
         this.expectedProviders.add(TwitterIdentityProviderFactory.PROVIDER_ID);
+        this.expectedProviders.add(LinkedInIdentityProviderFactory.PROVIDER_ID);
 
         this.expectedProviders = Collections.unmodifiableSet(this.expectedProviders);
     }
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java
index d2caacf..f596f1b 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/broker/ImportIdentityProviderTest.java
@@ -38,6 +38,8 @@ import org.keycloak.social.google.GoogleIdentityProvider;
 import org.keycloak.social.google.GoogleIdentityProviderFactory;
 import org.keycloak.social.twitter.TwitterIdentityProvider;
 import org.keycloak.social.twitter.TwitterIdentityProviderFactory;
+import org.keycloak.social.linkedin.LinkedInIdentityProvider;
+import org.keycloak.social.linkedin.LinkedInIdentityProviderFactory;
 
 import java.io.IOException;
 import java.util.HashSet;
@@ -160,6 +162,8 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
                     assertGitHubIdentityProviderConfig(identityProvider);
                 } else if (TwitterIdentityProviderFactory.PROVIDER_ID.equals(providerId)) {
                     assertTwitterIdentityProviderConfig(identityProvider);
+                } else if (LinkedInIdentityProviderFactory.PROVIDER_ID.equals(providerId)) {
+                    assertLinkedInIdentityProviderConfig(identityProvider);
                 } else {
                     continue;
                 }
@@ -257,6 +261,23 @@ public class ImportIdentityProviderTest extends AbstractIdentityProviderModelTes
         assertEquals(GitHubIdentityProvider.PROFILE_URL, config.getUserInfoUrl());
     }
 
+    private void assertLinkedInIdentityProviderConfig(IdentityProviderModel identityProvider) {
+      LinkedInIdentityProvider gitHubIdentityProvider = new LinkedInIdentityProviderFactory().create(identityProvider);
+      OAuth2IdentityProviderConfig config = gitHubIdentityProvider.getConfig();
+
+        assertEquals("model-linkedin", config.getAlias());
+      assertEquals(LinkedInIdentityProviderFactory.PROVIDER_ID, config.getProviderId());
+      assertEquals(true, config.isEnabled());
+      assertEquals(true, config.isUpdateProfileFirstLogin());
+      assertEquals(false, config.isAuthenticateByDefault());
+      assertEquals(false, config.isStoreToken());
+      assertEquals("clientId", config.getClientId());
+      assertEquals("clientSecret", config.getClientSecret());
+      assertEquals(LinkedInIdentityProvider.AUTH_URL, config.getAuthorizationUrl());
+      assertEquals(LinkedInIdentityProvider.TOKEN_URL, config.getTokenUrl());
+      assertEquals(LinkedInIdentityProvider.PROFILE_URL, config.getUserInfoUrl());
+    }
+
     private void assertTwitterIdentityProviderConfig(IdentityProviderModel identityProvider) {
         TwitterIdentityProvider twitterIdentityProvider = new TwitterIdentityProviderFactory().create(identityProvider);
         OAuth2IdentityProviderConfig config = twitterIdentityProvider.getConfig();
diff --git a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
index d08df51..96cdc96 100755
--- a/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
+++ b/testsuite/integration/src/test/resources/broker-test/test-realm-with-broker.json
@@ -62,6 +62,20 @@
             }
         },
         {
+            "alias" : "model-linkedin",
+            "providerId" : "linkedin",
+            "enabled": true,
+            "updateProfileFirstLogin" : "true",
+            "storeToken": false,
+            "config": {
+                "authorizationUrl": "authorizationUrl",
+                "tokenUrl": "tokenUrl",
+                "userInfoUrl": "userInfoUrl",
+                "clientId": "clientId",
+                "clientSecret": "clientSecret"
+            }
+        },
+        {
           "alias" : "model-saml-signed-idp",
           "providerId" : "saml",
           "enabled": true,
@@ -213,4 +227,4 @@
             }
         ]
     }
-}
\ No newline at end of file
+}