You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:18:09 UTC

[sling-org-apache-sling-auth-xing-login] annotated tag org.apache.sling.auth.xing.login-0.0.2 created (now c109030)

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a change to annotated tag org.apache.sling.auth.xing.login-0.0.2
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-auth-xing-login.git.


      at c109030  (tag)
 tagging 6a864bb7e9b3bbe32f1f3d08b40d8028b4a67b90 (commit)
      by Oliver Lietz
      on Tue Jul 8 14:40:11 2014 +0000

- Log -----------------------------------------------------------------
org.apache.sling.auth.xing.login-0.0.2
-----------------------------------------------------------------------

This annotated tag includes the following new commits:

     new 766c1ee  SLING-3731 SLING-3732 add Sling Authentication XING API, Sling Authentication XING OAuth and Sling Authentication XING Login
     new fb7499d  SLING-3731 SLING-3732 add scm settings
     new 5c9a962  style
     new 714ffc0  SLING-3732 add package info
     new 6c41ebe  SLING-3732 use org.apache.sling.auth.xing.api 0.0.2
     new 5428296  [maven-release-plugin] prepare release org.apache.sling.auth.xing.login-0.0.2
     new 6a864bb  [maven-release-plugin]  copy for tag org.apache.sling.auth.xing.login-0.0.2

The 7 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


-- 
To stop receiving notification emails like this one, please contact
['"commits@sling.apache.org" <co...@sling.apache.org>'].

[sling-org-apache-sling-auth-xing-login] 04/07: SLING-3732 add package info

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.auth.xing.login-0.0.2
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-auth-xing-login.git

commit 714ffc08e8338a87921675afb58e9a9edb855ab6
Author: Oliver Lietz <ol...@apache.org>
AuthorDate: Tue Jul 8 14:32:25 2014 +0000

    SLING-3732 add package info
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/auth/org.apache.sling.auth.xing.login@1608800 13f79535-47bb-0310-9956-ffa450edef68
---
 .../apache/sling/auth/xing/login/package-info.java   | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/src/main/java/org/apache/sling/auth/xing/login/package-info.java b/src/main/java/org/apache/sling/auth/xing/login/package-info.java
new file mode 100644
index 0000000..65d0036
--- /dev/null
+++ b/src/main/java/org/apache/sling/auth/xing/login/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+@aQute.bnd.annotation.Version("0.0.2")
+package org.apache.sling.auth.xing.login;

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-auth-xing-login] 03/07: style

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.auth.xing.login-0.0.2
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-auth-xing-login.git

commit 5c9a9623c85fe1448c7cc71661544d4483d3910b
Author: Oliver Lietz <ol...@apache.org>
AuthorDate: Tue Jul 8 14:31:05 2014 +0000

    style
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/auth/org.apache.sling.auth.xing.login@1608799 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/pom.xml b/pom.xml
index b90fbc9..3dc50f0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -103,20 +103,20 @@
     </dependency>
     <dependency>
       <groupId>org.apache.sling</groupId>
-      <artifactId>org.apache.sling.jcr.api</artifactId>
+      <artifactId>org.apache.sling.commons.osgi</artifactId>
       <version>2.2.0</version>
       <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.sling</groupId>
-      <artifactId>org.apache.sling.jcr.jackrabbit.server</artifactId>
-      <version>2.1.2</version>
+      <artifactId>org.apache.sling.jcr.api</artifactId>
+      <version>2.2.0</version>
       <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.apache.sling</groupId>
-      <artifactId>org.apache.sling.commons.osgi</artifactId>
-      <version>2.2.0</version>
+      <artifactId>org.apache.sling.jcr.jackrabbit.server</artifactId>
+      <version>2.1.2</version>
       <scope>provided</scope>
     </dependency>
     <!-- Apache Jackrabbit -->

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-auth-xing-login] 06/07: [maven-release-plugin] prepare release org.apache.sling.auth.xing.login-0.0.2

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.auth.xing.login-0.0.2
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-auth-xing-login.git

commit 54282964cea42a4d9d50eccb885c4427cfe875fe
Author: Oliver Lietz <ol...@apache.org>
AuthorDate: Tue Jul 8 14:40:08 2014 +0000

    [maven-release-plugin] prepare release org.apache.sling.auth.xing.login-0.0.2
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/auth/org.apache.sling.auth.xing.login@1608805 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/pom.xml b/pom.xml
index 326ca27..7cfbfb1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,7 +29,7 @@
   </parent>
 
   <artifactId>org.apache.sling.auth.xing.login</artifactId>
-  <version>0.0.1-SNAPSHOT</version>
+  <version>0.0.2</version>
   <packaging>bundle</packaging>
 
   <name>Apache Sling Authentication XING Login</name>
@@ -41,9 +41,9 @@
   </properties>
 
   <scm>
-    <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/auth/org.apache.sling.auth.xing.login</connection>
-    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/auth/org.apache.sling.auth.xing.login</developerConnection>
-    <url>http://svn.apache.org/viewvc/sling/trunk/contrib/auth/org.apache.sling.auth.xing.login</url>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/sling/tags/org.apache.sling.auth.xing.login-0.0.2</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.auth.xing.login-0.0.2</developerConnection>
+    <url>http://svn.apache.org/viewvc/sling/tags/org.apache.sling.auth.xing.login-0.0.2</url>
   </scm>
 
   <dependencies>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-auth-xing-login] 01/07: SLING-3731 SLING-3732 add Sling Authentication XING API, Sling Authentication XING OAuth and Sling Authentication XING Login

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.auth.xing.login-0.0.2
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-auth-xing-login.git

commit 766c1ee167c64630daa4716aa89a77f0158e0712
Author: Oliver Lietz <ol...@apache.org>
AuthorDate: Fri Jul 4 15:43:38 2014 +0000

    SLING-3731 SLING-3732 add Sling Authentication XING API, Sling Authentication XING OAuth and Sling Authentication XING Login
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/auth/org.apache.sling.auth.xing.login@1607877 13f79535-47bb-0310-9956-ffa450edef68
---
 README.md                                          |   5 +
 pom.xml                                            | 187 +++++++++++++++
 .../apache/sling/auth/xing/login/XingLogin.java    |  40 ++++
 .../auth/xing/login/XingLoginUserManager.java      |  30 +++
 .../sling/auth/xing/login/XingLoginUtil.java       | 108 +++++++++
 .../login/impl/DefaultXingLoginUserManager.java    | 214 +++++++++++++++++
 .../login/impl/XingLoginAuthenticationHandler.java | 262 +++++++++++++++++++++
 .../login/impl/XingLoginAuthenticationPlugin.java  |  90 +++++++
 .../login/impl/XingLoginLoginModulePlugin.java     | 120 ++++++++++
 .../OSGI-INF/metatype/metatype.properties          |  59 +++++
 10 files changed, 1115 insertions(+)

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..10d25e3
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+Apache Sling Authentication XING Login
+======================================
+
+* uses the cookie-based “[Login with XING](https://dev.xing.com/plugins/login_with)” for authentication
+* allows creating and updating JCR users based on supplied user data from XING
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..084e23d
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,187 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you 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.
+-->
+<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">
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.sling</groupId>
+    <artifactId>sling</artifactId>
+    <version>19</version>
+    <relativePath>../../../parent/pom.xml</relativePath>
+  </parent>
+
+  <artifactId>org.apache.sling.auth.xing.login</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <name>Apache Sling Authentication XING Login</name>
+
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+    <sling.java.version>6</sling.java.version>
+  </properties>
+
+  <dependencies>
+    <!-- javax -->
+    <dependency>
+      <groupId>javax.jcr</groupId>
+      <artifactId>jcr</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>servlet-api</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <!-- OSGi -->
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.compendium</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <!-- Apache Commons -->
+    <dependency>
+      <groupId>commons-codec</groupId>
+      <artifactId>commons-codec</artifactId>
+      <version>1.9</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>commons-lang</groupId>
+      <artifactId>commons-lang</artifactId>
+      <version>2.6</version>
+      <scope>provided</scope>
+    </dependency>
+    <!-- Apache Sling -->
+    <dependency>
+      <groupId>org.apache.sling</groupId>
+      <artifactId>org.apache.sling.api</artifactId>
+      <version>2.7.0</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.sling</groupId>
+      <artifactId>org.apache.sling.auth.core</artifactId>
+      <version>1.1.6</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.sling</groupId>
+      <artifactId>org.apache.sling.auth.xing.api</artifactId>
+      <version>0.0.1-SNAPSHOT</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.sling</groupId>
+      <artifactId>org.apache.sling.jcr.api</artifactId>
+      <version>2.2.0</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.sling</groupId>
+      <artifactId>org.apache.sling.jcr.jackrabbit.server</artifactId>
+      <version>2.1.2</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.sling</groupId>
+      <artifactId>org.apache.sling.commons.osgi</artifactId>
+      <version>2.2.0</version>
+      <scope>provided</scope>
+    </dependency>
+    <!-- Apache Jackrabbit -->
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>jackrabbit-api</artifactId>
+      <version>2.0.0</version>
+      <scope>provided</scope>
+    </dependency>
+    <!-- Apache Felix -->
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.scr.annotations</artifactId>
+      <scope>provided</scope>
+    </dependency>
+    <!-- Gson -->
+    <dependency>
+      <groupId>com.google.code.gson</groupId>
+      <artifactId>gson</artifactId>
+      <version>2.2.4</version>
+      <scope>compile</scope>
+    </dependency>
+    <!-- logging -->
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+      <version>1.7.7</version>
+      <scope>provided</scope>
+    </dependency>
+    <!-- testing -->
+    <dependency>
+      <groupId>org.testng</groupId>
+      <artifactId>testng</artifactId>
+      <version>6.8.8</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Category>sling</Bundle-Category>
+            <Embed-Dependency>
+              gson;inline=true,
+              org.apache.sling.commons.osgi;inline="org/apache/sling/commons/osgi/PropertiesUtil.*"
+            </Embed-Dependency>
+            <_removeheaders>
+              Embed-Dependency,
+              Private-Package,
+              Include-Resource
+            </_removeheaders>
+          </instructions>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-scr-plugin</artifactId>
+        <executions>
+          <execution>
+            <goals>
+              <goal>scr</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+
+</project>
diff --git a/src/main/java/org/apache/sling/auth/xing/login/XingLogin.java b/src/main/java/org/apache/sling/auth/xing/login/XingLogin.java
new file mode 100644
index 0000000..7028567
--- /dev/null
+++ b/src/main/java/org/apache/sling/auth/xing/login/XingLogin.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.sling.auth.xing.login;
+
+/**
+ * for <code>XING_COOKIE_PREFIX</code> and <code>HASH_ALGORITHM</code>
+ * see chapter <i>5. Server-side verification of the user data</i> from
+ * <code>Documentation-Login-with-XING-plugin-110414.pdf</code>
+ */
+public class XingLogin {
+
+    public static final String AUTH_TYPE = "xing-login";
+
+    public static final String AUTHENTICATION_CREDENTIALS_HASH_KEY = "xing-hash";
+
+    public static final String AUTHENTICATION_CREDENTIALS_USERDATA_KEY = "xing-userdata";
+
+    public static final String XING_COOKIE_PREFIX = "xing_p_lw_s_";
+
+    public static final String HASH_ALGORITHM = "HmacSHA256";
+
+    public static final String SERVICE_VENDOR = "The Apache Software Foundation";
+
+}
diff --git a/src/main/java/org/apache/sling/auth/xing/login/XingLoginUserManager.java b/src/main/java/org/apache/sling/auth/xing/login/XingLoginUserManager.java
new file mode 100644
index 0000000..41f41fc
--- /dev/null
+++ b/src/main/java/org/apache/sling/auth/xing/login/XingLoginUserManager.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.sling.auth.xing.login;
+
+import aQute.bnd.annotation.ProviderType;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.sling.auth.xing.api.XingUserManager;
+
+@ProviderType
+public interface XingLoginUserManager extends XingUserManager {
+
+    String getHash(User user);
+
+}
diff --git a/src/main/java/org/apache/sling/auth/xing/login/XingLoginUtil.java b/src/main/java/org/apache/sling/auth/xing/login/XingLoginUtil.java
new file mode 100644
index 0000000..dd2bfac
--- /dev/null
+++ b/src/main/java/org/apache/sling/auth/xing/login/XingLoginUtil.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.sling.auth.xing.login;
+
+import java.io.UnsupportedEncodingException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.jcr.Credentials;
+import javax.jcr.SimpleCredentials;
+
+import com.google.gson.FieldNamingPolicy;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.lang.StringUtils;
+import org.apache.sling.auth.xing.api.XingUser;
+
+public class XingLoginUtil {
+
+    public static String getHash(Credentials credentials) {
+        if (credentials instanceof SimpleCredentials) {
+            final SimpleCredentials simpleCredentials = (SimpleCredentials) credentials;
+            final Object attribute = simpleCredentials.getAttribute(XingLogin.AUTHENTICATION_CREDENTIALS_HASH_KEY);
+            if (attribute instanceof String) {
+                return (String) attribute;
+            }
+        }
+        return null;
+    }
+
+    public static String getUser(Credentials credentials) {
+        if (credentials instanceof SimpleCredentials) {
+            final SimpleCredentials simpleCredentials = (SimpleCredentials) credentials;
+            final Object attribute = simpleCredentials.getAttribute(XingLogin.AUTHENTICATION_CREDENTIALS_USERDATA_KEY);
+            if (attribute instanceof String) {
+                try {
+                    final String base64Json = (String) attribute;
+                    final byte[] decoded = Base64.decodeBase64(base64Json);
+                    return new String(decoded, "UTF-8");
+                } catch (Exception e) {
+                    // ignore
+                }
+            }
+        }
+        return null;
+    }
+
+    public static XingUser fromJson(final String json) {
+        final Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
+        return gson.fromJson(json, XingUser.class);
+    }
+
+    public static String hash(final String json, final String secretKey, final String hashAlgorithm) throws InvalidKeyException, NoSuchAlgorithmException, UnsupportedEncodingException {
+        final Gson gson = new Gson();
+        final List<String> list = new ArrayList<String>();
+        final Map map = gson.fromJson(json, Map.class);
+        join(map, list, "");
+        Collections.sort(list);
+        final String message = StringUtils.join(list, null);
+        final byte[] result = hmac(message, secretKey, hashAlgorithm);
+        return Hex.encodeHexString(result);
+    }
+
+    private static void join(final Map map, final List<String> list, final String prefix) {
+        final Set<Map.Entry> entrySet = map.entrySet();
+        for (Map.Entry entry : entrySet) {
+            if (entry.getValue() instanceof Map) {
+                final Map m = (Map) entry.getValue();
+                join(m, list, prefix.concat(entry.getKey().toString()));
+            } else {
+                list.add(prefix.concat(entry.getKey().toString()).concat(entry.getValue().toString()));
+            }
+        }
+    }
+
+    private static byte[] hmac(final String message, final String secretKey, final String hashAlgorithm) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
+        final SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), hashAlgorithm);
+        final Mac mac = Mac.getInstance(hashAlgorithm);
+        mac.init(secretKeySpec);
+        return mac.doFinal(message.getBytes("UTF-8"));
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/auth/xing/login/impl/DefaultXingLoginUserManager.java b/src/main/java/org/apache/sling/auth/xing/login/impl/DefaultXingLoginUserManager.java
new file mode 100644
index 0000000..c018e57
--- /dev/null
+++ b/src/main/java/org/apache/sling/auth/xing/login/impl/DefaultXingLoginUserManager.java
@@ -0,0 +1,214 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.sling.auth.xing.login.impl;
+
+import java.util.Dictionary;
+
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Modified;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.sling.auth.xing.api.AbstractXingUserManager;
+import org.apache.sling.auth.xing.api.XingUser;
+import org.apache.sling.auth.xing.login.XingLogin;
+import org.apache.sling.auth.xing.login.XingLoginUserManager;
+import org.apache.sling.auth.xing.login.XingLoginUtil;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(
+    label = "Apache Sling Authentication XING Login “Default User Manager”",
+    description = "Default User Manager for Sling Authentication XING Login",
+    immediate = true,
+    metatype = true
+)
+@Service
+@Properties({
+    @Property(name = Constants.SERVICE_VENDOR, value = XingLogin.SERVICE_VENDOR),
+    @Property(name = Constants.SERVICE_DESCRIPTION, value = "Default User Manager for Sling Authentication XING Login"),
+    @Property(name = Constants.SERVICE_RANKING, intValue = 0, propertyPrivate = false)
+})
+public class DefaultXingLoginUserManager extends AbstractXingUserManager implements XingLoginUserManager {
+
+    private String secretKey;
+
+    private String userDataProperty;
+
+    private String userHashProperty;
+
+    @Reference
+    private SlingRepository slingRepository;
+
+    private static final String DEFAULT_USER_DATA_PROPERTY = "data";
+
+    private static final String DEFAULT_USER_HASH_PROPERTY = "hash";
+
+    @Property(value = "")
+    private static final String SECRET_KEY_PARAMETER = "org.apache.sling.auth.xing.login.impl.DefaultXingLoginUserManager.secretKey";
+
+    @Property(value = DEFAULT_USER_DATA_PROPERTY)
+    private static final String USER_DATA_PROPERTY_PARAMETER = "org.apache.sling.auth.xing.login.impl.DefaultXingLoginUserManager.user.property.data";
+
+    @Property(value = DEFAULT_USER_HASH_PROPERTY)
+    private static final String USER_HASH_PROPERTY_PARAMETER = "org.apache.sling.auth.xing.login.impl.DefaultXingLoginUserManager.user.property.hash";
+
+    @Property(boolValue = DEFAULT_AUTO_CREATE_USER)
+    private static final String AUTO_CREATE_USER_PARAMETER = "org.apache.sling.auth.xing.login.impl.DefaultXingLoginUserManager.user.create.auto";
+
+    @Property(boolValue = DEFAULT_AUTO_UPDATE_USER)
+    private static final String AUTO_UPDATE_USER_PARAMETER = "org.apache.sling.auth.xing.login.impl.DefaultXingLoginUserManager.user.update.auto";
+
+    private final Logger logger = LoggerFactory.getLogger(DefaultXingLoginUserManager.class);
+
+    public DefaultXingLoginUserManager() {
+    }
+
+    @Activate
+    protected void activate(final ComponentContext componentContext) {
+        logger.debug("activate");
+        configure(componentContext);
+    }
+
+    @Modified
+    protected void modified(final ComponentContext componentContext) {
+        logger.debug("modified");
+        configure(componentContext);
+    }
+
+    @Deactivate
+    protected void deactivate(final ComponentContext componentContext) {
+        logger.debug("deactivate");
+        if (session != null) {
+            session.logout();
+            session = null;
+        }
+    }
+
+    protected synchronized void configure(final ComponentContext componentContext) {
+        final Dictionary properties = componentContext.getProperties();
+        secretKey = PropertiesUtil.toString(properties.get(SECRET_KEY_PARAMETER), "").trim();
+        userDataProperty = PropertiesUtil.toString(properties.get(USER_DATA_PROPERTY_PARAMETER), DEFAULT_USER_DATA_PROPERTY).trim();
+        userHashProperty = PropertiesUtil.toString(properties.get(USER_HASH_PROPERTY_PARAMETER), DEFAULT_USER_HASH_PROPERTY).trim();
+        autoCreateUser = PropertiesUtil.toBoolean(properties.get(AUTO_CREATE_USER_PARAMETER), DEFAULT_AUTO_CREATE_USER);
+        autoUpdateUser = PropertiesUtil.toBoolean(properties.get(AUTO_UPDATE_USER_PARAMETER), DEFAULT_AUTO_UPDATE_USER);
+
+        if (StringUtils.isEmpty(secretKey)) {
+            logger.warn("configured secret key is empty");
+        }
+    }
+
+    @Override
+    protected SlingRepository getSlingRepository() {
+        return slingRepository;
+    }
+
+    @Override
+    public User createUser(final Credentials credentials) {
+        logger.debug("create user");
+        return storeUser(credentials);
+    }
+
+    @Override
+    public User updateUser(Credentials credentials) {
+        logger.debug("update user");
+        return storeUser(credentials);
+    }
+
+    protected User storeUser(Credentials credentials) {
+        final String givenHash = XingLoginUtil.getHash(credentials);
+        final String json = XingLoginUtil.getUser(credentials);
+
+        if (givenHash == null || json == null) {
+            logger.debug("unable to get hash and/or user data from given credentials");
+            return null;
+        }
+
+        // validate user data with hash
+        try {
+            final String computedHash = XingLoginUtil.hash(json, secretKey, XingLogin.HASH_ALGORITHM);
+            final boolean match = givenHash.equals(computedHash);
+            if (!match) {
+                logger.warn("invalid hash or user data given, aborting");
+                return null;
+            }
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+            return null;
+        }
+
+        try {
+            final XingUser xingUser = XingLoginUtil.fromJson(json);
+            final String userId = xingUser.getId(); // TODO make configurable
+
+            User user = getUser(userId);
+            if (user == null) {
+                logger.debug("creating a new user with id '{}'", userId);
+                final Session session = getSession();
+                final UserManager userManager = getUserManager(session);
+                user = userManager.createUser(userId, null);
+            } else {
+                logger.debug("updating an existing user with id '{}'", userId);
+            }
+
+            // TODO disable user on create?
+            final ValueFactory valueFactory = getSession().getValueFactory();
+            final Value dataValue = valueFactory.createValue(json);
+            final Value hashValue = valueFactory.createValue(givenHash);
+            user.setProperty(userDataProperty, dataValue);
+            user.setProperty(userHashProperty, hashValue);
+            session.save();
+            return user;
+        } catch (Exception e) {
+            logger.error(e.getMessage(), e);
+            return null;
+        }
+    }
+
+    @Override
+    public String getHash(final User user) {
+        try {
+            final Value[] values = user.getProperty(userHashProperty);
+            if (values != null && values.length == 1) {
+                final Value value = values[0];
+                return value.getString();
+            }
+        } catch (RepositoryException e) {
+            logger.error(e.getMessage(), e);
+        }
+        return null;
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/auth/xing/login/impl/XingLoginAuthenticationHandler.java b/src/main/java/org/apache/sling/auth/xing/login/impl/XingLoginAuthenticationHandler.java
new file mode 100644
index 0000000..1d0fb1c
--- /dev/null
+++ b/src/main/java/org/apache/sling/auth/xing/login/impl/XingLoginAuthenticationHandler.java
@@ -0,0 +1,262 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.sling.auth.xing.login.impl;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Modified;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.PropertyUnbounded;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.sling.auth.core.AuthConstants;
+import org.apache.sling.auth.core.AuthUtil;
+import org.apache.sling.auth.core.spi.AuthenticationHandler;
+import org.apache.sling.auth.core.spi.AuthenticationInfo;
+import org.apache.sling.auth.core.spi.DefaultAuthenticationFeedbackHandler;
+import org.apache.sling.auth.xing.login.XingLogin;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(
+    label = "Apache Sling Authentication XING Login “Authentication Handler”",
+    description = "Authentication Handler for Sling Authentication XING Login",
+    immediate = true,
+    metatype = true
+)
+@Service
+@Properties({
+    @Property(name = Constants.SERVICE_VENDOR, value = XingLogin.SERVICE_VENDOR),
+    @Property(name = Constants.SERVICE_DESCRIPTION, value = "Authentication Handler for Sling Authentication XING Login"),
+    @Property(name = Constants.SERVICE_RANKING, intValue = 0, propertyPrivate = false),
+    @Property(name = AuthenticationHandler.PATH_PROPERTY, value = "/", unbounded = PropertyUnbounded.ARRAY),
+    @Property(name = AuthenticationHandler.TYPE_PROPERTY, value = XingLogin.AUTH_TYPE, propertyPrivate = true)
+})
+public class XingLoginAuthenticationHandler extends DefaultAuthenticationFeedbackHandler implements AuthenticationHandler {
+
+    private String consumerKey;
+
+    private String xingCookie;
+
+    private String userCookie;
+
+    private String userIdCookie;
+
+    private int maxCookieSize;
+
+    private String loginPath;
+
+    private String logoutPath;
+
+    private ServiceRegistration loginPageRegistration;
+
+    private static final String DEFAULT_USER_COOKIE = "sling_auth_xing_user";
+
+    private static final String DEFAULT_USERID_COOKIE = "sling_auth_xing_userid";
+
+    private static final int DEFAULT_MAX_COOKIE_SIZE = 4096;
+
+    @Property(value = "")
+    private static final String CONSUMER_KEY_PARAMETER = "org.apache.sling.auth.xing.login.impl.XingLoginAuthenticationHandler.consumerKey";
+
+    @Property(value = DEFAULT_USER_COOKIE)
+    private static final String USER_COOKIE_PARAMETER = "org.apache.sling.auth.xing.login.impl.XingLoginAuthenticationHandler.cookie.user";
+
+    @Property(value = DEFAULT_USERID_COOKIE)
+    private static final String USERID_COOKIE_PARAMETER = "org.apache.sling.auth.xing.login.impl.XingLoginAuthenticationHandler.cookie.userid";
+
+    @Property(intValue = DEFAULT_MAX_COOKIE_SIZE)
+    private static final String MAX_COOKIE_SIZE_PARAMETER = "org.apache.sling.auth.xing.login.impl.XingLoginAuthenticationHandler.cookie.maxSize";
+
+    @Property
+    private static final String LOGIN_PATH_PARAMETER = "org.apache.sling.auth.xing.login.impl.XingLoginAuthenticationHandler.login.path";
+
+    @Property
+    private static final String LOGOUT_PATH_PARAMETER = "org.apache.sling.auth.xing.login.impl.XingLoginAuthenticationHandler.logout.path";
+
+    private final Logger logger = LoggerFactory.getLogger(XingLoginAuthenticationHandler.class);
+
+    public XingLoginAuthenticationHandler() {
+    }
+
+    @Activate
+    protected void activate(final ComponentContext ComponentContext) {
+        logger.debug("activate");
+        configure(ComponentContext);
+    }
+
+    @Modified
+    protected void modified(final ComponentContext ComponentContext) {
+        logger.debug("modified");
+        configure(ComponentContext);
+    }
+
+    @Deactivate
+    protected void deactivate(final ComponentContext ComponentContext) {
+        logger.debug("deactivate");
+        if (loginPageRegistration != null) {
+            loginPageRegistration.unregister();
+            loginPageRegistration = null;
+        }
+    }
+
+    protected void configure(final ComponentContext context) {
+        final Dictionary properties = context.getProperties();
+        consumerKey = PropertiesUtil.toString(properties.get(CONSUMER_KEY_PARAMETER), "").trim();
+        userCookie = PropertiesUtil.toString(properties.get(USER_COOKIE_PARAMETER), DEFAULT_USER_COOKIE).trim();
+        userIdCookie = PropertiesUtil.toString(properties.get(USERID_COOKIE_PARAMETER), DEFAULT_USERID_COOKIE).trim();
+        maxCookieSize = PropertiesUtil.toInteger(properties.get(MAX_COOKIE_SIZE_PARAMETER), DEFAULT_MAX_COOKIE_SIZE);
+        loginPath = PropertiesUtil.toString(properties.get(LOGIN_PATH_PARAMETER), "").trim();
+        logoutPath = PropertiesUtil.toString(properties.get(LOGOUT_PATH_PARAMETER), "").trim();
+
+        if (StringUtils.isEmpty(consumerKey)) {
+            logger.warn("configured consumer key is empty");
+            xingCookie = "";
+        } else {
+            xingCookie = XingLogin.XING_COOKIE_PREFIX.concat(consumerKey);
+        }
+
+        if (loginPageRegistration != null) {
+            loginPageRegistration.unregister();
+        }
+
+        if (StringUtils.isEmpty(loginPath)) {
+            logger.warn("configured login path is empty");
+        } else {
+            final Dictionary<String, Object> loginPathProperties = new Hashtable<String, Object>();
+            final String[] authRequirements = new String[]{"-".concat(loginPath)};
+            loginPathProperties.put(AuthConstants.AUTH_REQUIREMENTS, authRequirements);
+            loginPageRegistration = context.getBundleContext().registerService(Object.class.getName(), new Object(), loginPathProperties);
+        }
+
+        if (StringUtils.isEmpty(logoutPath)) {
+            logger.warn("configured logout path is empty");
+        }
+
+        logger.info("configured with consumer key '{}', cookie name '{}', login path '{}' and logout path '{}'", consumerKey, xingCookie, loginPath, logoutPath);
+    }
+
+    /**
+     * we need the <i>hash</i> from the XING cookie (<code>xing_p_lw_s_[...]</code>) and
+     * the <i>user data</i> and <i>id</i> from our own cookies (<code>sling_auth_xing_[...]</code>)
+     *
+     * @param request
+     * @param response
+     * @return
+     */
+    @Override
+    public AuthenticationInfo extractCredentials(final HttpServletRequest request, final HttpServletResponse response) {
+        logger.debug("extract credentials");
+
+        String hash = null;
+        String user = null;
+        String userId = null;
+
+        final Cookie[] cookies = request.getCookies();
+        if (cookies != null) {
+            for (final Cookie cookie : cookies) {
+                final String cookieName = cookie.getName();
+                if (cookieName.equals(xingCookie)) {
+                    hash = readCookieValue(cookie);
+                    logger.debug("“Login with XING” cookie found: {}", hash);
+                } else if (cookieName.equals(userCookie)) {
+                    user = readCookieValue(cookie);
+                } else if (cookieName.equals(userIdCookie)) {
+                    userId = readCookieValue(cookie);
+                }
+            }
+        }
+
+        if (!StringUtils.isEmpty(hash) && !StringUtils.isEmpty(userId) && !StringUtils.isEmpty(user)) {
+            logger.debug("valid cookies with hash and user data and id found");
+            final AuthenticationInfo authenticationInfo = new AuthenticationInfo(XingLogin.AUTH_TYPE, userId);
+            authenticationInfo.put(XingLogin.AUTHENTICATION_CREDENTIALS_HASH_KEY, hash);
+            authenticationInfo.put(XingLogin.AUTHENTICATION_CREDENTIALS_USERDATA_KEY, user);
+            return authenticationInfo;
+        } else {
+            logger.debug("unable to extract credentials from request");
+            return null;
+        }
+    }
+
+    @Override
+    public boolean requestCredentials(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
+        logger.debug("request credentials");
+        if (!loginPath.equals(request.getServletPath())) {
+            final String target = request.getContextPath().concat(loginPath);
+            logger.debug("redirecting to '{}'", target);
+            AuthUtil.sendRedirect(request, response, target, null);
+        }
+        return true;
+    }
+
+    @Override
+    public void dropCredentials(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
+        logger.debug("drop credentials");
+        // delete cookies
+        deleteCookies(request, response);
+        // redirect and call JavaScript xing.logout()
+        final HashMap<String, String> params = new HashMap<String, String>();
+        logger.debug("redirecting to '{}'", logoutPath);
+        AuthUtil.sendRedirect(request, response, logoutPath, params);
+    }
+
+    protected String readCookieValue(final Cookie cookie) {
+        if (cookie.getValue() != null) {
+            if (cookie.getValue().length() > maxCookieSize) {
+                logger.warn("size of cookie value greater than configured max. cookie size of {}", maxCookieSize);
+            } else {
+                return cookie.getValue();
+            }
+        }
+        return null;
+    }
+
+    protected void deleteCookies(final HttpServletRequest request, final HttpServletResponse response) {
+        final Cookie[] cookies = request.getCookies();
+        if (cookies != null) {
+            for (final Cookie cookie : cookies) {
+                final String name = cookie.getName();
+                logger.debug("cookie found: '{}'", name);
+                if (name.equals(xingCookie) || name.equals(userCookie) || name.equals(userIdCookie)) {
+                    logger.debug("deleting cookie '{}' with value '{}'", cookie.getName(), cookie.getValue());
+                    cookie.setValue(null);
+                    cookie.setMaxAge(0);
+                    response.addCookie(cookie);
+                }
+            }
+        }
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/auth/xing/login/impl/XingLoginAuthenticationPlugin.java b/src/main/java/org/apache/sling/auth/xing/login/impl/XingLoginAuthenticationPlugin.java
new file mode 100644
index 0000000..dac0729
--- /dev/null
+++ b/src/main/java/org/apache/sling/auth/xing/login/impl/XingLoginAuthenticationPlugin.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.sling.auth.xing.login.impl;
+
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.sling.auth.xing.login.XingLoginUserManager;
+import org.apache.sling.auth.xing.login.XingLoginUtil;
+import org.apache.sling.jcr.jackrabbit.server.security.AuthenticationPlugin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class XingLoginAuthenticationPlugin implements AuthenticationPlugin {
+
+    private final XingLoginUserManager xingLoginUserManager;
+
+    private final Logger logger = LoggerFactory.getLogger(XingLoginAuthenticationPlugin.class);
+
+    public XingLoginAuthenticationPlugin(final XingLoginUserManager xingLoginUserManager) {
+        this.xingLoginUserManager = xingLoginUserManager;
+    }
+
+    @Override
+    public boolean authenticate(final Credentials credentials) throws RepositoryException {
+        logger.debug("authenticate");
+
+        // check if given credentials have a hash
+        final String givenHash = XingLoginUtil.getHash(credentials);
+        if (givenHash == null) {
+            logger.debug("unable to get hash from given credentials");
+            return false;
+        }
+
+        User user = xingLoginUserManager.getUser(credentials);
+        if (user == null) { // check if given credentials pull up an existing user
+            logger.debug("no user found for given credentials");
+            if (xingLoginUserManager.autoCreate()) {
+                logger.debug("creating a new user from given user data");
+                // validating with hash happens in createUser(credentials)
+                user = xingLoginUserManager.createUser(credentials);
+            }
+        }
+
+        // re-check
+        if (user == null) {
+            return false;
+        }
+
+        // check if stored user has a hash
+        final String storedHash = xingLoginUserManager.getHash(user);
+        if (storedHash == null) { // should not happen, so return false
+            logger.debug("no hash found for user '{}'", user.getID());
+            return false;
+        }
+
+        // check if hashes match
+        if (givenHash.equals(storedHash)) {
+            logger.debug("hashes for user '{}' do match", user.getID());
+            return true;
+        } else {
+            logger.debug("hashes for user '{}' do not match", user.getID());
+            if (xingLoginUserManager.autoUpdate()) {
+                logger.debug("updating an existing user from given user data");
+                // validating with hash happens in updateUser(credentials)
+                return xingLoginUserManager.updateUser(credentials) != null;
+            }
+        }
+
+        return false;
+    }
+
+}
diff --git a/src/main/java/org/apache/sling/auth/xing/login/impl/XingLoginLoginModulePlugin.java b/src/main/java/org/apache/sling/auth/xing/login/impl/XingLoginLoginModulePlugin.java
new file mode 100644
index 0000000..4e78e0c
--- /dev/null
+++ b/src/main/java/org/apache/sling/auth/xing/login/impl/XingLoginLoginModulePlugin.java
@@ -0,0 +1,120 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.apache.sling.auth.xing.login.impl;
+
+import java.security.Principal;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.FailedLoginException;
+import javax.security.auth.login.LoginException;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Properties;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.sling.auth.xing.login.XingLogin;
+import org.apache.sling.auth.xing.login.XingLoginUserManager;
+import org.apache.sling.auth.xing.login.XingLoginUtil;
+import org.apache.sling.jcr.jackrabbit.server.security.AuthenticationPlugin;
+import org.apache.sling.jcr.jackrabbit.server.security.LoginModulePlugin;
+import org.osgi.framework.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(
+    label = "Apache Sling Authentication XING Login “Login Module Plugin”",
+    description = "Login Module Plugin for Sling Authentication XING Login",
+    immediate = true,
+    metatype = true
+)
+@Service
+@Properties({
+    @Property(name = Constants.SERVICE_VENDOR, value = XingLogin.SERVICE_VENDOR),
+    @Property(name = Constants.SERVICE_DESCRIPTION, value = "Login Module Plugin for Sling Authentication XING Login"),
+    @Property(name = Constants.SERVICE_RANKING, intValue = 0, propertyPrivate = false)
+})
+/**
+ * @see org.apache.jackrabbit.core.security.authentication.DefaultLoginModule
+ */
+public class XingLoginLoginModulePlugin implements LoginModulePlugin {
+
+    @Reference
+    private XingLoginUserManager xingLoginUserManager;
+
+    private final Logger logger = LoggerFactory.getLogger(XingLoginLoginModulePlugin.class);
+
+    public XingLoginLoginModulePlugin() {
+    }
+
+    @Override
+    public boolean canHandle(final Credentials credentials) {
+        logger.debug("canHandle({})", credentials);
+        final String hash = XingLoginUtil.getHash(credentials);
+        final String user = XingLoginUtil.getUser(credentials);
+        logger.debug("hash: {}, user: {}", hash, user);
+        return hash != null && user != null;
+    }
+
+    @Override
+    public void doInit(final CallbackHandler callbackHandler, final Session session, final Map map) throws LoginException {
+        logger.debug("doInit({}, {}, {})", callbackHandler, session, map);
+    }
+
+    @Override
+    public Principal getPrincipal(final Credentials credentials) {
+        logger.debug("getPrincipal({})", credentials);
+        try {
+            User user = xingLoginUserManager.getUser(credentials);
+            if (user == null && xingLoginUserManager.autoCreate()) {
+                user = xingLoginUserManager.createUser(credentials);
+            }
+            if (user != null) {
+                return user.getPrincipal();
+            }
+        } catch (RepositoryException e) {
+            logger.error(e.getMessage(), e);
+        }
+        return null;
+    }
+
+    @Override
+    public void addPrincipals(final Set set) {
+        logger.debug("addPrincipals({})", set);
+    }
+
+    @Override
+    public AuthenticationPlugin getAuthentication(final Principal principal, final Credentials credentials) throws RepositoryException {
+        logger.debug("getAuthentication({}, {})", principal, credentials);
+        return new XingLoginAuthenticationPlugin(xingLoginUserManager);
+    }
+
+    @Override
+    public int impersonate(final Principal principal, final Credentials credentials) throws RepositoryException, FailedLoginException {
+        logger.debug("impersonate({}, {})", principal, credentials);
+        return LoginModulePlugin.IMPERSONATION_DEFAULT;
+    }
+
+}
diff --git a/src/main/resources/OSGI-INF/metatype/metatype.properties b/src/main/resources/OSGI-INF/metatype/metatype.properties
new file mode 100644
index 0000000..05e475f
--- /dev/null
+++ b/src/main/resources/OSGI-INF/metatype/metatype.properties
@@ -0,0 +1,59 @@
+#
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you 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.
+#
+
+path.name = path
+path.description = the path or paths this service is in charge for
+
+service.ranking.name = service ranking
+service.ranking.description = service property for identifying the service's ranking number
+
+# Authentication Handler
+org.apache.sling.auth.xing.login.impl.XingLoginAuthenticationHandler.consumerKey.name = consumer key
+org.apache.sling.auth.xing.login.impl.XingLoginAuthenticationHandler.consumerKey.description = consumer key from XING
+
+org.apache.sling.auth.xing.login.impl.XingLoginAuthenticationHandler.cookie.user.name = user cookie
+org.apache.sling.auth.xing.login.impl.XingLoginAuthenticationHandler.cookie.user.description = cookie to read the encoded (BASE64) user data (JSON) from
+
+org.apache.sling.auth.xing.login.impl.XingLoginAuthenticationHandler.cookie.userid.name =  user id cookie
+org.apache.sling.auth.xing.login.impl.XingLoginAuthenticationHandler.cookie.userid.description = cookie to read user id from
+
+org.apache.sling.auth.xing.login.impl.XingLoginAuthenticationHandler.cookie.maxSize.name = max. cookie size
+org.apache.sling.auth.xing.login.impl.XingLoginAuthenticationHandler.cookie.maxSize.description = maximal number of characters to use for processing from cookie's value
+
+org.apache.sling.auth.xing.login.impl.XingLoginAuthenticationHandler.login.path.name = login path
+org.apache.sling.auth.xing.login.impl.XingLoginAuthenticationHandler.login.path.description = path to redirect to for login
+
+org.apache.sling.auth.xing.login.impl.XingLoginAuthenticationHandler.logout.path.name = logout path
+org.apache.sling.auth.xing.login.impl.XingLoginAuthenticationHandler.logout.path.description = path to redirect to for logout
+
+# User Manager
+org.apache.sling.auth.xing.login.impl.DefaultXingLoginUserManager.secretKey.name = secret key
+org.apache.sling.auth.xing.login.impl.DefaultXingLoginUserManager.secretKey.description = secret key from XING (given as signature salt)
+
+org.apache.sling.auth.xing.login.impl.DefaultXingLoginUserManager.user.property.data.name = data property
+org.apache.sling.auth.xing.login.impl.DefaultXingLoginUserManager.user.property.data.description = property where to store the user data from XING in an user
+
+org.apache.sling.auth.xing.login.impl.DefaultXingLoginUserManager.user.property.hash.name = hash property
+org.apache.sling.auth.xing.login.impl.DefaultXingLoginUserManager.user.property.hash.description = property where to store the hash from XING in an user
+
+org.apache.sling.auth.xing.login.impl.DefaultXingLoginUserManager.user.create.auto.name = create user automatically
+org.apache.sling.auth.xing.login.impl.DefaultXingLoginUserManager.user.create.auto.description = create a new JCR user automatically with given and validated user data from XING
+
+org.apache.sling.auth.xing.login.impl.DefaultXingLoginUserManager.user.update.auto.name = update user automatically
+org.apache.sling.auth.xing.login.impl.DefaultXingLoginUserManager.user.update.auto.description = update an existing JCR user automatically with given and validated user data from XING

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-auth-xing-login] 07/07: [maven-release-plugin] copy for tag org.apache.sling.auth.xing.login-0.0.2

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.auth.xing.login-0.0.2
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-auth-xing-login.git

commit 6a864bb7e9b3bbe32f1f3d08b40d8028b4a67b90
Author: Oliver Lietz <ol...@apache.org>
AuthorDate: Tue Jul 8 14:40:11 2014 +0000

    [maven-release-plugin]  copy for tag org.apache.sling.auth.xing.login-0.0.2
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/tags/org.apache.sling.auth.xing.login-0.0.2@1608806 13f79535-47bb-0310-9956-ffa450edef68

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-auth-xing-login] 05/07: SLING-3732 use org.apache.sling.auth.xing.api 0.0.2

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.auth.xing.login-0.0.2
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-auth-xing-login.git

commit 6c41ebe619782108187b0eb72783498ae7963fea
Author: Oliver Lietz <ol...@apache.org>
AuthorDate: Tue Jul 8 14:34:19 2014 +0000

    SLING-3732 use org.apache.sling.auth.xing.api 0.0.2
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/auth/org.apache.sling.auth.xing.login@1608802 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pom.xml b/pom.xml
index 3dc50f0..326ca27 100644
--- a/pom.xml
+++ b/pom.xml
@@ -98,7 +98,7 @@
     <dependency>
       <groupId>org.apache.sling</groupId>
       <artifactId>org.apache.sling.auth.xing.api</artifactId>
-      <version>0.0.1-SNAPSHOT</version>
+      <version>0.0.2</version>
       <scope>provided</scope>
     </dependency>
     <dependency>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.

[sling-org-apache-sling-auth-xing-login] 02/07: SLING-3731 SLING-3732 add scm settings

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.auth.xing.login-0.0.2
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-auth-xing-login.git

commit fb7499da1167523a371c7a8b88b4b6878a7ba023
Author: Oliver Lietz <ol...@apache.org>
AuthorDate: Mon Jul 7 06:24:04 2014 +0000

    SLING-3731 SLING-3732 add scm settings
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/contrib/auth/org.apache.sling.auth.xing.login@1608345 13f79535-47bb-0310-9956-ffa450edef68
---
 pom.xml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/pom.xml b/pom.xml
index 084e23d..b90fbc9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,6 +40,12 @@
     <sling.java.version>6</sling.java.version>
   </properties>
 
+  <scm>
+    <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/contrib/auth/org.apache.sling.auth.xing.login</connection>
+    <developerConnection>scm:svn:https://svn.apache.org/repos/asf/sling/trunk/contrib/auth/org.apache.sling.auth.xing.login</developerConnection>
+    <url>http://svn.apache.org/viewvc/sling/trunk/contrib/auth/org.apache.sling.auth.xing.login</url>
+  </scm>
+
   <dependencies>
     <!-- javax -->
     <dependency>

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.