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:14 UTC
[sling-org-apache-sling-auth-xing-oauth] 01/08: SLING-3731
SLING-3732 add Sling Authentication XING API,
Sling Authentication XING OAuth and Sling Authentication XING Login
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to annotated tag org.apache.sling.auth.xing.oauth-0.0.2
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-auth-xing-oauth.git
commit 41d61afc2141ca497730c957e7cb92e907a69fac
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.oauth@1607877 13f79535-47bb-0310-9956-ffa450edef68
---
README.md | 5 +
pom.xml | 197 +++++++++++++++++
.../apache/sling/auth/xing/oauth/XingOauth.java | 31 +++
.../auth/xing/oauth/XingOauthUserManager.java | 27 +++
.../sling/auth/xing/oauth/XingOauthUtil.java | 51 +++++
.../oauth/impl/DefaultXingOauthUserManager.java | 182 ++++++++++++++++
.../oauth/impl/XingOauthAuthenticationHandler.java | 239 +++++++++++++++++++++
.../oauth/impl/XingOauthAuthenticationPlugin.java | 69 ++++++
.../oauth/impl/XingOauthLoginModulePlugin.java | 122 +++++++++++
.../apache/sling/auth/xing/oauth/package-info.java | 20 ++
.../OSGI-INF/metatype/metatype.properties | 44 ++++
11 files changed, 987 insertions(+)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..d688ec7
--- /dev/null
+++ b/README.md
@@ -0,0 +1,5 @@
+Apache Sling Authentication XING OAuth
+======================================
+
+* uses the [XING API](https://dev.xing.com/docs) with OAuth 1.0 for [authentication](https://dev.xing.com/docs/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..267e5a0
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,197 @@
+<?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.oauth</artifactId>
+ <version>0.0.1-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <name>Apache Sling Authentication XING OAuth</name>
+ <description>Apache Sling Authentication XING OAuth</description>
+
+ <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>
+ <version>2.0</version>
+ <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-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.commons.osgi</artifactId>
+ <version>2.2.0</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>
+ <!-- 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>
+ <!-- bndlib -->
+ <dependency>
+ <groupId>biz.aQute.bnd</groupId>
+ <artifactId>bndlib</artifactId>
+ <version>2.3.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <!-- Scribe OAuth -->
+ <dependency>
+ <groupId>org.scribe</groupId>
+ <artifactId>scribe</artifactId>
+ <version>1.3.5</version>
+ <scope>compile</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>
+ *;scope=compile;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/oauth/XingOauth.java b/src/main/java/org/apache/sling/auth/xing/oauth/XingOauth.java
new file mode 100644
index 0000000..944add2
--- /dev/null
+++ b/src/main/java/org/apache/sling/auth/xing/oauth/XingOauth.java
@@ -0,0 +1,31 @@
+/*
+ * 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.oauth;
+
+public class XingOauth {
+
+ public static final String AUTH_TYPE = "xing-oauth";
+
+ public static final String AUTHENTICATION_CREDENTIALS_ACCESS_TOKEN_KEY = "xing-access-token";
+
+ public static final String AUTHENTICATION_CREDENTIALS_USER_KEY = "xing-user";
+
+ public static final String SERVICE_VENDOR = "The Apache Software Foundation";
+
+}
diff --git a/src/main/java/org/apache/sling/auth/xing/oauth/XingOauthUserManager.java b/src/main/java/org/apache/sling/auth/xing/oauth/XingOauthUserManager.java
new file mode 100644
index 0000000..6d158f4
--- /dev/null
+++ b/src/main/java/org/apache/sling/auth/xing/oauth/XingOauthUserManager.java
@@ -0,0 +1,27 @@
+/*
+ * 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.oauth;
+
+import aQute.bnd.annotation.ProviderType;
+import org.apache.sling.auth.xing.api.XingUserManager;
+
+@ProviderType
+public interface XingOauthUserManager extends XingUserManager {
+
+}
diff --git a/src/main/java/org/apache/sling/auth/xing/oauth/XingOauthUtil.java b/src/main/java/org/apache/sling/auth/xing/oauth/XingOauthUtil.java
new file mode 100644
index 0000000..81c2f21
--- /dev/null
+++ b/src/main/java/org/apache/sling/auth/xing/oauth/XingOauthUtil.java
@@ -0,0 +1,51 @@
+/*
+ * 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.oauth;
+
+import javax.jcr.Credentials;
+import javax.jcr.SimpleCredentials;
+
+import org.apache.sling.auth.xing.api.XingUser;
+import org.scribe.model.Token;
+
+public class XingOauthUtil {
+
+ public static Token getAccessToken(Credentials credentials) {
+ if (credentials instanceof SimpleCredentials) {
+ final SimpleCredentials simpleCredentials = (SimpleCredentials) credentials;
+ final Object attribute = simpleCredentials.getAttribute(XingOauth.AUTHENTICATION_CREDENTIALS_ACCESS_TOKEN_KEY);
+ if (attribute instanceof Token) {
+ return (Token) attribute;
+ }
+ }
+ return null;
+ }
+
+ public static XingUser getXingUser(Credentials credentials) {
+ if (credentials instanceof SimpleCredentials) {
+ final SimpleCredentials simpleCredentials = (SimpleCredentials) credentials;
+ final Object attribute = simpleCredentials.getAttribute(XingOauth.AUTHENTICATION_CREDENTIALS_USER_KEY);
+ if (attribute instanceof XingUser) {
+ return (XingUser) attribute;
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/auth/xing/oauth/impl/DefaultXingOauthUserManager.java b/src/main/java/org/apache/sling/auth/xing/oauth/impl/DefaultXingOauthUserManager.java
new file mode 100644
index 0000000..a82d47e
--- /dev/null
+++ b/src/main/java/org/apache/sling/auth/xing/oauth/impl/DefaultXingOauthUserManager.java
@@ -0,0 +1,182 @@
+/*
+ * 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.oauth.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.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.oauth.XingOauth;
+import org.apache.sling.auth.xing.oauth.XingOauthUserManager;
+import org.apache.sling.auth.xing.oauth.XingOauthUtil;
+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 OAuth “Default User Manager”",
+ description = "Default User Manager for Sling Authentication XING OAuth",
+ immediate = true,
+ metatype = true
+)
+@Service
+@Properties({
+ @Property(name = Constants.SERVICE_VENDOR, value = XingOauth.SERVICE_VENDOR),
+ @Property(name = Constants.SERVICE_DESCRIPTION, value = "Default User Manager for Sling Authentication XING OAuth"),
+ @Property(name = Constants.SERVICE_RANKING, intValue = 0, propertyPrivate = false)
+})
+public class DefaultXingOauthUserManager extends AbstractXingUserManager implements XingOauthUserManager {
+
+ @Reference
+ private SlingRepository slingRepository;
+
+ private static final String FIRSTNAME_PROPERTY = "firstname";
+
+ private static final String LASTNAME_PROPERTY = "lastname";
+
+ @Property(boolValue = DEFAULT_AUTO_CREATE_USER)
+ private static final String AUTO_CREATE_USER_PARAMETER = "org.apache.sling.auth.xing.oauth.impl.DefaultXingOauthUserManager.user.create.auto";
+
+ @Property(boolValue = DEFAULT_AUTO_UPDATE_USER)
+ private static final String AUTO_UPDATE_USER_PARAMETER = "org.apache.sling.auth.xing.oauth.impl.DefaultXingOauthUserManager.user.update.auto";
+
+ private final Logger logger = LoggerFactory.getLogger(DefaultXingOauthUserManager.class);
+
+ public DefaultXingOauthUserManager() {
+ }
+
+ @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();
+ 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);
+ }
+
+ @Override
+ protected SlingRepository getSlingRepository() {
+ return slingRepository;
+ }
+
+ @Override
+ public User createUser(final Credentials credentials) {
+ logger.debug("create user");
+ final XingUser xingUser = XingOauthUtil.getXingUser(credentials);
+ if (xingUser == null) {
+ return null;
+ }
+
+ try {
+ final String userId = xingUser.getId(); // TODO make configurable
+
+ final Session session = getSession();
+ final UserManager userManager = getUserManager(session);
+ final User user = userManager.createUser(userId, null);
+
+ // TODO disable user on create?
+ final ValueFactory valueFactory = session.getValueFactory();
+ final Value firstnameValue = valueFactory.createValue(xingUser.getFirstName());
+ final Value lastnameValue = valueFactory.createValue(xingUser.getLastName());
+ user.setProperty(FIRSTNAME_PROPERTY, firstnameValue);
+ user.setProperty(LASTNAME_PROPERTY, lastnameValue);
+ session.save();
+ return user;
+ } catch (Exception e) {
+ logger.error(e.getMessage(), e);
+ return null;
+ }
+ }
+
+ @Override
+ public User updateUser(Credentials credentials) {
+ logger.debug("update user");
+ final XingUser xingUser = XingOauthUtil.getXingUser(credentials);
+ if (xingUser == null) {
+ return null;
+ }
+
+ try {
+ final Session session = getSession();
+ final User user = getUser(credentials);
+ final ValueFactory valueFactory = session.getValueFactory();
+
+ final boolean firstnameUpdated = updateUserProperty(user, valueFactory, FIRSTNAME_PROPERTY, xingUser.getFirstName());
+ final boolean lastnameUpdated = updateUserProperty(user, valueFactory, LASTNAME_PROPERTY, xingUser.getLastName());
+ if (firstnameUpdated || lastnameUpdated) {
+ session.save();
+ }
+
+ return user;
+ } catch (Exception e) {
+ logger.error(e.getMessage(), e);
+ return null;
+ }
+ }
+
+ private boolean updateUserProperty(final User user, final ValueFactory valueFactory, final String property, final String string) throws RepositoryException {
+ final Value[] values = user.getProperty(property);
+ if (values != null && values.length > 0) {
+ if (string.equals(values[0].getString())) {
+ return false;
+ }
+ }
+ final Value value = valueFactory.createValue(string);
+ user.setProperty(property, value);
+ return true;
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/auth/xing/oauth/impl/XingOauthAuthenticationHandler.java b/src/main/java/org/apache/sling/auth/xing/oauth/impl/XingOauthAuthenticationHandler.java
new file mode 100644
index 0000000..79f58d0
--- /dev/null
+++ b/src/main/java/org/apache/sling/auth/xing/oauth/impl/XingOauthAuthenticationHandler.java
@@ -0,0 +1,239 @@
+/*
+ * 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.oauth.impl;
+
+import java.io.IOException;
+import java.util.Dictionary;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import com.google.gson.FieldNamingPolicy;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+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.spi.AuthenticationHandler;
+import org.apache.sling.auth.core.spi.AuthenticationInfo;
+import org.apache.sling.auth.core.spi.DefaultAuthenticationFeedbackHandler;
+import org.apache.sling.auth.xing.api.XingUser;
+import org.apache.sling.auth.xing.api.users.Users;
+import org.apache.sling.auth.xing.oauth.XingOauth;
+import org.apache.sling.commons.osgi.PropertiesUtil;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+import org.scribe.builder.ServiceBuilder;
+import org.scribe.builder.api.XingApi;
+import org.scribe.model.OAuthConstants;
+import org.scribe.model.OAuthRequest;
+import org.scribe.model.Response;
+import org.scribe.model.Token;
+import org.scribe.model.Verb;
+import org.scribe.model.Verifier;
+import org.scribe.oauth.OAuthService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(
+ label = "Apache Sling Authentication XING OAuth “Authentication Handler”",
+ description = "Authentication Handler for Sling Authentication XING OAuth",
+ immediate = true,
+ metatype = true
+)
+@Service
+@Properties({
+ @Property(name = Constants.SERVICE_VENDOR, value = XingOauth.SERVICE_VENDOR),
+ @Property(name = Constants.SERVICE_DESCRIPTION, value = "Authentication Handler for Sling Authentication XING OAuth"),
+ @Property(name = Constants.SERVICE_RANKING, intValue = 0, propertyPrivate = false),
+ @Property(name = AuthenticationHandler.PATH_PROPERTY, value = "/", unbounded = PropertyUnbounded.ARRAY),
+ @Property(name = AuthenticationHandler.TYPE_PROPERTY, value = XingOauth.AUTH_TYPE, propertyPrivate = true)
+})
+public class XingOauthAuthenticationHandler extends DefaultAuthenticationFeedbackHandler implements AuthenticationHandler {
+
+ private OAuthService oAuthService;
+
+ private String consumerKey;
+
+ private String consumerSecret;
+
+ private String callbackUrl;
+
+ private String usersMeUrl;
+
+ private static final String DEFAULT_USERS_ME_URL = "https://api.xing.com/v1/users/me.json";
+
+ @Property(value = "")
+ private static final String CONSUMER_KEY_PARAMETER = "org.apache.sling.auth.xing.oauth.impl.XingOauthAuthenticationHandler.consumerKey";
+
+ @Property(value = "")
+ private static final String CONSUMER_SECRET_PARAMETER = "org.apache.sling.auth.xing.oauth.impl.XingOauthAuthenticationHandler.consumerSecret";
+
+ @Property(value = "")
+ private static final String CALLBACK_URL_PARAMETER = "org.apache.sling.auth.xing.oauth.impl.XingOauthAuthenticationHandler.callbackUrl";
+
+ @Property(value = DEFAULT_USERS_ME_URL)
+ private static final String USERS_ME_URL_PARAMETER = "org.apache.sling.auth.xing.oauth.impl.XingOauthAuthenticationHandler.usersMeUrl";
+
+ public static final String USER_SESSION_ATTRIBUTE_NAME = "xing-user";
+
+ private final Logger logger = LoggerFactory.getLogger(XingOauthAuthenticationHandler.class);
+
+ public XingOauthAuthenticationHandler() {
+ }
+
+ @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");
+ }
+
+ protected synchronized void configure(final ComponentContext componentContext) {
+ final Dictionary properties = componentContext.getProperties();
+ consumerKey = PropertiesUtil.toString(properties.get(CONSUMER_KEY_PARAMETER), "").trim();
+ consumerSecret = PropertiesUtil.toString(properties.get(CONSUMER_SECRET_PARAMETER), "").trim();
+ callbackUrl = PropertiesUtil.toString(properties.get(CALLBACK_URL_PARAMETER), "").trim();
+ usersMeUrl = PropertiesUtil.toString(properties.get(USERS_ME_URL_PARAMETER), DEFAULT_USERS_ME_URL).trim();
+
+ if (StringUtils.isEmpty(consumerKey)) {
+ logger.warn("configured consumer key is empty");
+ }
+
+ if (StringUtils.isEmpty(consumerSecret)) {
+ logger.warn("configured consumer secret is empty");
+ }
+
+ if (StringUtils.isEmpty(callbackUrl)) {
+ logger.warn("configured callback URL is empty");
+ }
+
+ if (StringUtils.isEmpty(usersMeUrl)) {
+ logger.warn("configured users me URL is empty");
+ }
+
+ if (!StringUtils.isEmpty(consumerKey) && !StringUtils.isEmpty(consumerSecret) && !StringUtils.isEmpty(callbackUrl)) {
+ oAuthService = new ServiceBuilder().provider(XingApi.class).apiKey(consumerKey).apiSecret(consumerSecret).callback(callbackUrl).build();
+ }
+
+ logger.info("configured with consumer key '{}', callback url '{}' and users me url '{}'", consumerKey, callbackUrl, usersMeUrl);
+ }
+
+ // we need the OAuth access token and the user from XING (/v1/users/me)
+ @Override
+ public AuthenticationInfo extractCredentials(final HttpServletRequest request, final HttpServletResponse response) {
+ logger.debug("extract credentials");
+
+ try {
+ final HttpSession httpSession = request.getSession(true);
+
+ Token accessToken = (Token) httpSession.getAttribute(OAuthConstants.ACCESS_TOKEN);
+ XingUser xingUser = (XingUser) httpSession.getAttribute(USER_SESSION_ATTRIBUTE_NAME);
+
+ if (accessToken == null) {
+ // we need the request token and verifier to get an access token
+ final Token requestToken = (Token) httpSession.getAttribute(OAuthConstants.TOKEN);
+ final String verifier = request.getParameter(OAuthConstants.VERIFIER);
+ if (requestToken == null || verifier == null) {
+ return null;
+ }
+ accessToken = oAuthService.getAccessToken(requestToken, new Verifier(verifier));
+ logger.debug("access token: {}", accessToken);
+ httpSession.setAttribute(OAuthConstants.ACCESS_TOKEN, accessToken);
+ }
+
+ if (xingUser == null) {
+ xingUser = fetchUser(accessToken);
+ logger.debug("xing user: {}", xingUser);
+ httpSession.setAttribute(USER_SESSION_ATTRIBUTE_NAME, xingUser);
+ }
+
+ final AuthenticationInfo authenticationInfo = new AuthenticationInfo(XingOauth.AUTH_TYPE, xingUser.getId());
+ authenticationInfo.put(XingOauth.AUTHENTICATION_CREDENTIALS_ACCESS_TOKEN_KEY, accessToken);
+ authenticationInfo.put(XingOauth.AUTHENTICATION_CREDENTIALS_USER_KEY, xingUser);
+ return authenticationInfo;
+ } catch (Exception e) {
+ logger.error(e.getMessage(), e);
+ removeAuthFromSession(request);
+ return null;
+ }
+ }
+
+ @Override
+ public boolean requestCredentials(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
+ logger.debug("request credentials");
+ try {
+ final Token requestToken = oAuthService.getRequestToken();
+ logger.debug("received request token: '{}'", requestToken);
+ final HttpSession httpSession = request.getSession(true);
+ httpSession.setAttribute(OAuthConstants.TOKEN, requestToken);
+ final String authUrl = oAuthService.getAuthorizationUrl(requestToken);
+ logger.debug("redirecting to auth url: '{}'", authUrl);
+ response.sendRedirect(authUrl);
+ return true;
+ } catch (Exception e) {
+ logger.error(e.getMessage(), e);
+ return false;
+ }
+ }
+
+ @Override
+ public void dropCredentials(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
+ logger.debug("drop credentials");
+ removeAuthFromSession(request);
+ }
+
+ protected XingUser fetchUser(final Token accessToken) throws Exception {
+ final OAuthRequest request = new OAuthRequest(Verb.GET, usersMeUrl);
+ oAuthService.signRequest(accessToken, request);
+ final Response response = request.send();
+ final Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
+ final Users users = gson.fromJson(response.getBody(), Users.class);
+ return users.getUsers().get(0);
+ }
+
+ protected void removeAuthFromSession(final HttpServletRequest request) {
+ try {
+ final HttpSession httpSession = request.getSession();
+ httpSession.removeAttribute(OAuthConstants.TOKEN);
+ httpSession.removeAttribute(OAuthConstants.ACCESS_TOKEN);
+ httpSession.removeAttribute(USER_SESSION_ATTRIBUTE_NAME);
+ } catch (Exception e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/auth/xing/oauth/impl/XingOauthAuthenticationPlugin.java b/src/main/java/org/apache/sling/auth/xing/oauth/impl/XingOauthAuthenticationPlugin.java
new file mode 100644
index 0000000..6be5d90
--- /dev/null
+++ b/src/main/java/org/apache/sling/auth/xing/oauth/impl/XingOauthAuthenticationPlugin.java
@@ -0,0 +1,69 @@
+/*
+ * 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.oauth.impl;
+
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.sling.auth.xing.api.XingUser;
+import org.apache.sling.auth.xing.oauth.XingOauthUserManager;
+import org.apache.sling.auth.xing.oauth.XingOauthUtil;
+import org.apache.sling.jcr.jackrabbit.server.security.AuthenticationPlugin;
+import org.scribe.model.Token;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class XingOauthAuthenticationPlugin implements AuthenticationPlugin {
+
+ final XingOauthUserManager xingOauthUserManager;
+
+ private final Logger logger = LoggerFactory.getLogger(XingOauthAuthenticationPlugin.class);
+
+ public XingOauthAuthenticationPlugin(final XingOauthUserManager xingOauthUserManager) {
+ this.xingOauthUserManager = xingOauthUserManager;
+ }
+
+ @Override
+ public boolean authenticate(final Credentials credentials) throws RepositoryException {
+ logger.debug("authenticate");
+
+ final Token accessToken = XingOauthUtil.getAccessToken(credentials);
+ final XingUser xingUser = XingOauthUtil.getXingUser(credentials);
+ if (accessToken == null || xingUser == null) {
+ return false;
+ }
+
+ User user = xingOauthUserManager.getUser(credentials);
+ if (user == null) { // check if given credentials pulled up an existing user
+ logger.debug("no user found for given credentials");
+ if (xingOauthUserManager.autoCreate()) {
+ logger.debug("creating a new user from given user data");
+ user = xingOauthUserManager.createUser(credentials);
+ }
+ } else {
+ if (xingOauthUserManager.autoUpdate()) {
+ xingOauthUserManager.updateUser(credentials);
+ }
+ }
+
+ return user != null;
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/auth/xing/oauth/impl/XingOauthLoginModulePlugin.java b/src/main/java/org/apache/sling/auth/xing/oauth/impl/XingOauthLoginModulePlugin.java
new file mode 100644
index 0000000..a52b494
--- /dev/null
+++ b/src/main/java/org/apache/sling/auth/xing/oauth/impl/XingOauthLoginModulePlugin.java
@@ -0,0 +1,122 @@
+/*
+ * 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.oauth.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.api.XingUser;
+import org.apache.sling.auth.xing.oauth.XingOauth;
+import org.apache.sling.auth.xing.oauth.XingOauthUserManager;
+import org.apache.sling.auth.xing.oauth.XingOauthUtil;
+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.scribe.model.Token;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(
+ label = "Apache Sling Authentication XING OAuth “Login Module Plugin”",
+ description = "Login Module Plugin for Sling Authentication XING OAuth",
+ immediate = true,
+ metatype = true
+)
+@Service
+@Properties({
+ @Property(name = Constants.SERVICE_VENDOR, value = XingOauth.SERVICE_VENDOR),
+ @Property(name = Constants.SERVICE_DESCRIPTION, value = "Login Module Plugin for Sling Authentication XING OAuth"),
+ @Property(name = Constants.SERVICE_RANKING, intValue = 0, propertyPrivate = false)
+})
+/**
+ * @see org.apache.jackrabbit.core.security.authentication.DefaultLoginModule
+ */
+public class XingOauthLoginModulePlugin implements LoginModulePlugin {
+
+ @Reference
+ private XingOauthUserManager xingOauthUserManager;
+
+ private final Logger logger = LoggerFactory.getLogger(XingOauthLoginModulePlugin.class);
+
+ public XingOauthLoginModulePlugin() {
+ }
+
+ @Override
+ public boolean canHandle(final Credentials credentials) {
+ logger.debug("canHandle({})", credentials);
+ final Token accessToken = XingOauthUtil.getAccessToken(credentials);
+ final XingUser xingUser = XingOauthUtil.getXingUser(credentials);
+ logger.debug("access token: {}, xing user: {}", accessToken, xingUser);
+ return accessToken != null && xingUser != 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 = xingOauthUserManager.getUser(credentials);
+ if (user == null && xingOauthUserManager.autoCreate()) {
+ user = xingOauthUserManager.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 XingOauthAuthenticationPlugin(xingOauthUserManager);
+ }
+
+ @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/java/org/apache/sling/auth/xing/oauth/package-info.java b/src/main/java/org/apache/sling/auth/xing/oauth/package-info.java
new file mode 100644
index 0000000..747ee1e
--- /dev/null
+++ b/src/main/java/org/apache/sling/auth/xing/oauth/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.1")
+package org.apache.sling.auth.xing.oauth;
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..da67f6e
--- /dev/null
+++ b/src/main/resources/OSGI-INF/metatype/metatype.properties
@@ -0,0 +1,44 @@
+#
+# 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.oauth.impl.XingOauthAuthenticationHandler.consumerKey.name = consumer key
+org.apache.sling.auth.xing.oauth.impl.XingOauthAuthenticationHandler.consumerKey.description = consumer key from XING
+
+org.apache.sling.auth.xing.oauth.impl.XingOauthAuthenticationHandler.consumerSecret.name = consumer secret
+org.apache.sling.auth.xing.oauth.impl.XingOauthAuthenticationHandler.consumerSecret.description = consumer secret from XING
+
+org.apache.sling.auth.xing.oauth.impl.XingOauthAuthenticationHandler.callbackUrl.name = callback URL
+org.apache.sling.auth.xing.oauth.impl.XingOauthAuthenticationHandler.callbackUrl.description = URL to redirect the user-agent after authorization has been granted
+
+org.apache.sling.auth.xing.oauth.impl.XingOauthAuthenticationHandler.usersMeUrl.name = user's profile URL
+org.apache.sling.auth.xing.oauth.impl.XingOauthAuthenticationHandler.usersMeUrl.description = URL of the web service to get the user's profile
+
+# User Manager
+org.apache.sling.auth.xing.oauth.impl.DefaultXingOauthUserManager.user.create.auto.name = create user automatically
+org.apache.sling.auth.xing.oauth.impl.DefaultXingOauthUserManager.user.create.auto.description = create a new JCR user automatically with given user data from XING
+
+org.apache.sling.auth.xing.oauth.impl.DefaultXingOauthUserManager.user.update.auto.name = update user automatically
+org.apache.sling.auth.xing.oauth.impl.DefaultXingOauthUserManager.user.update.auto.description = update an existing JCR user automatically with given user data from XING
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.