Author: anil.saldhana(a)jboss.com
Date: 2011-09-22 14:55:32 -0400 (Thu, 22 Sep 2011)
New Revision: 1248
Added:
social/trunk/social/
social/trunk/social/pom.xml
social/trunk/social/src/
social/trunk/social/src/main/
social/trunk/social/src/main/java/
social/trunk/social/src/main/java/org/
social/trunk/social/src/main/java/org/picketlink/
social/trunk/social/src/main/java/org/picketlink/social/
social/trunk/social/src/main/java/org/picketlink/social/auth/
social/trunk/social/src/main/java/org/picketlink/social/auth/ExternalAuthLoginModule.java
social/trunk/social/src/main/java/org/picketlink/social/auth/ExternalAuthenticator.java
Modified:
social/trunk/pom.xml
Log:
social module for consolidated external authentication
Modified: social/trunk/pom.xml
===================================================================
--- social/trunk/pom.xml 2011-09-22 18:54:35 UTC (rev 1247)
+++ social/trunk/pom.xml 2011-09-22 18:55:32 UTC (rev 1248)
@@ -17,6 +17,7 @@
<module>parent</module>
<module>openid</module>
<module>facebook</module>
+ <module>social</module>
</modules>
<reporting>
Added: social/trunk/social/pom.xml
===================================================================
--- social/trunk/social/pom.xml (rev 0)
+++ social/trunk/social/pom.xml 2011-09-22 18:55:32 UTC (rev 1248)
@@ -0,0 +1,204 @@
+<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/maven-v4_0_0.xsd">
+ <parent>
+ <groupId>org.picketlink</groupId>
+ <artifactId>picketlink-fed-parent</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ <relativePath>../parent</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <artifactId>picketlink-social</artifactId>
+ <packaging>jar</packaging>
+ <name>PicketLink Social</name>
+ <
url>http://labs.jboss.org/portal/picketlink/</url>
+ <description>PicketLink Social</description>
+ <licenses>
+ <license>
+ <name>lgpl</name>
+ <
url>http://repository.jboss.com/licenses/lgpl.txt</url>
+ </license>
+ </licenses>
+ <organization>
+ <name>JBoss Inc.</name>
+ <url>http://www.jboss.org</url>
+ </organization>
+
+ <profiles>
+
+ <profile>
+ <id>long-tests</id>
+ <activation>
+ <activeByDefault>false</activeByDefault>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.4.3</version>
+ <configuration>
+ <childDelegation>true</childDelegation>
+ <printSummary>true</printSummary>
+ <disableXmlReport>false</disableXmlReport>
+ <testFailureIgnore>false</testFailureIgnore>
+ <includes>
+ <include>**/integration/*TestCase.java</include>
+ </includes>
+ <forkMode>pertest</forkMode>
+ <argLine>${surefire.jvm.args}</argLine>
+ <useFile>false</useFile>
+ <trimStackTrace>false</trimStackTrace>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>2.7.1</version>
+ <configuration>
+ <additionalClasspathElements>
+
<additionalClasspathElement>${basedir}/src/test/resources/endorsed/xercesImpl.jar</additionalClasspathElement>
+ </additionalClasspathElements>
+ <printSummary>true</printSummary>
+ <disableXmlReport>false</disableXmlReport>
+ <testFailureIgnore>false</testFailureIgnore>
+ <includes>
+ <include>**/**TestCase.java</include>
+ </includes>
+ <forkMode>pertest</forkMode>
+
<argLine>-Djava.endorsed.dirs=${basedir}/src/test/resources/endorsed</argLine>
+ <useFile>false</useFile>
+ <trimStackTrace>false</trimStackTrace>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.json</groupId>
+ <artifactId>json</artifactId>
+ <version>20090211</version>
+ </dependency>
+ <dependency>
+ <groupId>org.picketlink</groupId>
+ <artifactId>picketlink-facebook</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.picketlink</groupId>
+ <artifactId>picketlink-openid</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.picketlink</groupId>
+ <artifactId>picketlink-fed-model</artifactId>
+ <version>2.0.1.final</version>
+ </dependency>
+ <dependency>
+ <groupId>org.picketlink</groupId>
+ <artifactId>picketlink-web</artifactId>
+ <version>2.0.1.final</version>
+ </dependency>
+ <dependency>
+ <groupId>org.openid4java</groupId>
+ <artifactId>openid4java-nodeps</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>apache-log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.14</version>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jetty</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tomcat</groupId>
+ <artifactId>jasper</artifactId>
+ <version>6.0.29</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.tomcat</groupId>
+ <artifactId>catalina</artifactId>
+ <version>6.0.18</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>apache-log4j</groupId>
+ <artifactId>log4j</artifactId>
+ <version>1.2.14</version>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>httpunit</groupId>
+ <artifactId>httpunit</artifactId>
+ <version>1.5.4</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>nekohtml</groupId>
+ <artifactId>nekohtml</artifactId>
+ <version>1.9.12</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-httpclient</groupId>
+ <artifactId>commons-httpclient</artifactId>
+ <version>3.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>xalan</groupId>
+ <artifactId>xalan</artifactId>
+ <version>2.7.1</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <doclet>org.jboss.apiviz.APIviz</doclet>
+ <docletArtifact>
+ <groupId>org.jboss.apiviz</groupId>
+ <artifactId>apiviz</artifactId>
+ <version>1.2.5.GA</version>
+ </docletArtifact>
+ <additionalparam>
+ -charset UTF-8
+ -docencoding UTF-8
+ -version
+ -author
+ -breakiterator
+ -windowtitle "${project.name} ${project.version} API Reference"
+ -doctitle "${project.name} ${project.version} API Reference"
+ -bottom "Copyright © ${project.inceptionYear}-Present
${project.organization.name}. All Rights Reserved."
+ -link
http://java.sun.com/javase/6/docs/api/
+ -sourceclasspath ${project.build.outputDirectory}
+ </additionalparam>
+ <encoding>UTF-8</encoding>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+</project>
Property changes on: social/trunk/social/pom.xml
___________________________________________________________________
Added: svn:executable
+ *
Added:
social/trunk/social/src/main/java/org/picketlink/social/auth/ExternalAuthLoginModule.java
===================================================================
---
social/trunk/social/src/main/java/org/picketlink/social/auth/ExternalAuthLoginModule.java
(rev 0)
+++
social/trunk/social/src/main/java/org/picketlink/social/auth/ExternalAuthLoginModule.java 2011-09-22
18:55:32 UTC (rev 1248)
@@ -0,0 +1,89 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2011, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.picketlink.social.auth;
+
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.List;
+
+import javax.security.auth.login.LoginException;
+import javax.security.auth.spi.LoginModule;
+
+import org.jboss.security.SimpleGroup;
+import org.jboss.security.SimplePrincipal;
+import org.jboss.security.auth.spi.UsernamePasswordLoginModule;
+import org.picketlink.social.facebook.FacebookProcessor;
+import org.picketlink.social.openid.auth.OpenIDProcessor;
+
+/**
+ * A {@link LoginModule} for JBoss environment to support external 3rd party
authentication
+ * @author Anil Saldhana
+ * @since Sep 22, 2011
+ */
+public class ExternalAuthLoginModule extends UsernamePasswordLoginModule
+{
+ @Override
+ protected Principal getIdentity()
+ {
+ Principal principal = null;
+ //Try facebook
+ principal = FacebookProcessor.cachedPrincipal.get();
+ if(principal == null )
+ principal = OpenIDProcessor.cachedPrincipal.get();
+ return principal;
+ }
+
+ @Override
+ protected String getUsersPassword() throws LoginException
+ {
+ return OpenIDProcessor.EMPTY_PASSWORD;
+ }
+
+ @Override
+ protected Group[] getRoleSets() throws LoginException
+ {
+ Group group = new SimpleGroup("Roles");
+
+ List<String> roles = OpenIDProcessor.cachedRoles.get();
+
+ if(roles != null)
+ {
+ for(String role: roles)
+ {
+ group.addMember(new SimplePrincipal(role));
+ }
+ }
+ roles = FacebookProcessor.cachedRoles.get();
+ if(roles != null)
+ {
+ for(String role: roles)
+ {
+ Principal rolePrincipal = new SimplePrincipal(role);
+ if(group.isMember(rolePrincipal) == false)
+ {
+ group.addMember(rolePrincipal);
+ }
+ }
+ }
+ return new Group[] {group};
+ }
+}
\ No newline at end of file
Added:
social/trunk/social/src/main/java/org/picketlink/social/auth/ExternalAuthenticator.java
===================================================================
---
social/trunk/social/src/main/java/org/picketlink/social/auth/ExternalAuthenticator.java
(rev 0)
+++
social/trunk/social/src/main/java/org/picketlink/social/auth/ExternalAuthenticator.java 2011-09-22
18:55:32 UTC (rev 1248)
@@ -0,0 +1,270 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2011, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.picketlink.social.auth;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.apache.catalina.Session;
+import org.apache.catalina.authenticator.Constants;
+import org.apache.catalina.authenticator.FormAuthenticator;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.deploy.LoginConfig;
+import org.apache.log4j.Logger;
+import org.picketlink.social.facebook.FacebookProcessor;
+import org.picketlink.social.openid.auth.OpenIDConsumerAuthenticator;
+import org.picketlink.social.openid.auth.OpenIDProcessor;
+
+/**
+ * Authenticator that performs authentication with
+ * external providers such as facebook, google, yahoo etc.
+ * @author Anil Saldhana
+ * @since Sep 22, 2011
+ */
+public class ExternalAuthenticator extends FormAuthenticator
+{
+ protected static Logger log = Logger.getLogger(OpenIDConsumerAuthenticator.class);
+ protected boolean trace = log.isTraceEnabled();
+
+ private enum AUTH_PROVIDERS
+ {
+ FACEBOOK, OPENID;
+ }
+
+ public static final String AUTH_TYPE = "authType";
+
+ protected FacebookProcessor facebookProcessor;
+ protected OpenIDProcessor openidProcessor;
+
+ protected String returnURL;
+ protected String clientID;
+ protected String clientSecret;
+ protected String facebookScope = "email";
+
+ private String requiredAttributes =
"name,email,ax_firstName,ax_lastName,ax_fullName";
+
+ private String optionalAttributes = null;
+
+ //Whether the authenticator has to to save and restore request
+ protected boolean saveRestoreRequest = true;
+
+ private enum STATES { AUTH, AUTHZ, FINISH};
+
+ public void setRoleString(String roleStr)
+ {
+ if(roleStr == null)
+ throw new RuntimeException("Role String is null in configuration");
+ StringTokenizer st = new StringTokenizer(roleStr, ",");
+ while(st.hasMoreElements())
+ {
+ roles.add(st.nextToken());
+ }
+ }
+
+ public void setSaveRestoreRequest(boolean saveRestoreRequest)
+ {
+ this.saveRestoreRequest = saveRestoreRequest;
+ }
+
+ protected List<String> roles = new ArrayList<String>();
+
+ public void setReturnURL(String returnURL)
+ {
+ this.returnURL = returnURL;
+ }
+ public void setClientID(String clientID)
+ {
+ this.clientID = clientID;
+ }
+ public void setClientSecret(String clientSecret)
+ {
+ this.clientSecret = clientSecret;
+ }
+ public void setFacebookScope(String facebookScope)
+ {
+ this.facebookScope = facebookScope;
+ }
+
+ public boolean authenticate(HttpServletRequest request, HttpServletResponse response,
LoginConfig loginConfig) throws IOException
+ {
+ if(request instanceof Request == false)
+ throw new IOException("Not of type Catalina request");
+ if(response instanceof Response == false)
+ throw new IOException("Not of type Catalina response");
+ return authenticate((Request)request, (Response)response, loginConfig);
+ }
+
+ public boolean authenticate(Request request, Response response, LoginConfig
loginConfig) throws IOException
+ {
+ if(trace) log.trace("authenticate");
+
+ if(facebookProcessor == null)
+ facebookProcessor = new FacebookProcessor(clientID, clientSecret, facebookScope,
returnURL, roles);
+
+ if(openidProcessor == null)
+ openidProcessor = new OpenIDProcessor(returnURL, requiredAttributes,
optionalAttributes);
+
+ HttpSession session = request.getSession();
+ //Determine the type of service based on request param
+ String authType = request.getParameter(AUTH_TYPE);
+ if(authType != null && authType.length() > 0)
+ {
+ //Place it on the session
+ session.setAttribute(AUTH_TYPE, authType);
+ }
+ if(authType == null || authType.length() == 0)
+ {
+ authType = (String) session.getAttribute(AUTH_TYPE);
+ }
+ if(authType == null)
+ {
+ authType = AUTH_PROVIDERS.FACEBOOK.name();
+ }
+ if(authType != null && authType.equals(AUTH_PROVIDERS.FACEBOOK.name()))
+ {
+ return processFacebook(request, response);
+ }
+ else
+ {
+ return processOpenID(request, response);
+ }
+ }
+
+ protected boolean processFacebook(Request request, Response response) throws
IOException
+ {
+ HttpSession session = request.getSession();
+ String state = (String) session.getAttribute("STATE");
+
+ if(trace) log.trace("state="+ state);
+
+ if( STATES.FINISH.name().equals(state))
+ return true;
+
+ if( state == null || state.isEmpty())
+ {
+ if (saveRestoreRequest)
+ {
+ this.saveRequest(request, request.getSessionInternal());
+ }
+ return facebookProcessor.initialInteraction(request, response);
+ }
+ //We have sent an auth request
+ if( state.equals(STATES.AUTH.name()))
+ {
+ return facebookProcessor.handleAuthStage(request, response);
+ }
+
+ //Principal facebookPrincipal = null;
+ if( state.equals(STATES.AUTHZ.name()))
+ {
+ Principal principal = facebookProcessor.getPrincipal(request, response,
context.getRealm());
+
+ if(principal == null)
+ throw new RuntimeException("Principal was null. Maybe login modules need
to be configured properly.");
+
+ String userName = principal.getName();
+
+ request.getSessionInternal().setNote(Constants.SESS_USERNAME_NOTE, userName);
+ request.getSessionInternal().setNote(Constants.SESS_PASSWORD_NOTE,
"");
+ request.setUserPrincipal(principal);
+
+ if (saveRestoreRequest)
+ {
+ this.restoreRequest(request, request.getSessionInternal());
+ }
+ register(request, response, principal, Constants.FORM_METHOD, userName,
"");
+ request.getSession().setAttribute("STATE", STATES.FINISH.name());
+
+ return true;
+ }
+ return false;
+ }
+
+ protected boolean processOpenID(Request request, Response response) throws
IOException
+ {
+ Principal userPrincipal = request.getUserPrincipal();
+ if(userPrincipal != null)
+ {
+ if(trace)
+ log.trace("Logged in as:"+userPrincipal);
+ return true;
+ }
+
+ if(!openidProcessor.isInitialized())
+ {
+ try
+ {
+ openidProcessor.initialize(roles);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ HttpSession httpSession = request.getSession();
+ String state = (String) httpSession.getAttribute("STATE");
+ if(trace) log.trace("state="+ state);
+
+ if( STATES.FINISH.name().equals(state))
+ return true;
+
+ if( state == null || state.isEmpty())
+ {
+ return openidProcessor.prepareAndSendAuthRequest(request, response);
+ }
+ //We have sent an auth request
+ if( state.equals(STATES.AUTH.name()))
+ {
+ Session session = request.getSessionInternal(true);
+ if (saveRestoreRequest)
+ {
+ this.saveRequest(request, session);
+ }
+
+ Principal principal = openidProcessor.processIncomingAuthResult(request,
response, context.getRealm());
+ String principalName = principal.getName();
+ request.getSessionInternal().setNote(Constants.SESS_USERNAME_NOTE,
principalName);
+ request.getSessionInternal().setNote(Constants.SESS_PASSWORD_NOTE,
"");
+ request.setUserPrincipal(principal);
+
+ if (saveRestoreRequest)
+ {
+ this.restoreRequest(request, request.getSessionInternal());
+ }
+
+ if(trace)
+ log.trace("Logged in as:" + principal);
+ register(request, response, principal, Constants.FORM_METHOD, principalName,
"");
+ return true;
+ }
+ return false;
+ }
+}
\ No newline at end of file