Author: anil.saldhana(a)jboss.com
Date: 2011-09-13 16:10:47 -0400 (Tue, 13 Sep 2011)
New Revision: 1220
Added:
federation/trunk/picketlink-bindings-jboss/src/main/java/org/picketlink/identity/federation/bindings/jboss/subject/PicketLinkJBossSubjectInteraction.java
federation/trunk/picketlink-bindings/src/main/java/org/picketlink/identity/federation/bindings/tomcat/SubjectSecurityInteraction.java
Modified:
federation/trunk/picketlink-bindings/src/main/java/org/picketlink/identity/federation/bindings/tomcat/PicketLinkAuthenticator.java
Log:
PLFED-229: PicketLink Authenticator has issues due to custom username that does not
change
Modified:
federation/trunk/picketlink-bindings/src/main/java/org/picketlink/identity/federation/bindings/tomcat/PicketLinkAuthenticator.java
===================================================================
---
federation/trunk/picketlink-bindings/src/main/java/org/picketlink/identity/federation/bindings/tomcat/PicketLinkAuthenticator.java 2011-09-13
04:14:10 UTC (rev 1219)
+++
federation/trunk/picketlink-bindings/src/main/java/org/picketlink/identity/federation/bindings/tomcat/PicketLinkAuthenticator.java 2011-09-13
20:10:47 UTC (rev 1220)
@@ -23,9 +23,17 @@
import java.io.IOException;
import java.security.Principal;
+import java.util.Set;
+import java.util.UUID;
+import javax.security.auth.Subject;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
import org.apache.catalina.Realm;
-import org.apache.catalina.authenticator.AuthenticatorBase;
+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;
@@ -40,27 +48,29 @@
* @author Anil.Saldhana(a)redhat.com
* @since Apr 11, 2011
*/
-public class PicketLinkAuthenticator extends AuthenticatorBase
+public class PicketLinkAuthenticator extends FormAuthenticator
{
protected static Logger log = Logger.getLogger(PicketLinkAuthenticator.class);
protected boolean trace = log.isTraceEnabled();
/**
- * The {@link Realm} requires an user name
+ * This is the auth method used in the register method
*/
- protected String userName = "custom-authenticator-user";
+ protected String authMethod = "SECURITY_DOMAIN";
/**
- * The {@link Realm} requires a password
+ * The authenticator may not be aware of the user name until after
+ * the underlying security exercise is complete. The Subject
+ * will have the proper user name. Hence we may need to perform
+ * an additional authentication now with the user name we have obtained.
*/
- protected String password = "custom-authenticator-password";
+ protected boolean needSubjectPrincipalSubstitution = true;
- /**
- * This is the auth method used in the register method
- */
- protected String authMethod = "SECURITY_DOMAIN";
+ protected SubjectSecurityInteraction subjectInteraction = null;
+ protected String subjectInteractionClassName =
"org.picketlink.identity.federation.bindings.jboss.subject.PicketLinkJBossSubjectInteraction";
+
public PicketLinkAuthenticator()
{
if (trace)
@@ -70,44 +80,102 @@
}
/**
- * Set the user name via WEB-INF/context.xml (JBoss AS)
- * @param defaultUserName
+ * Set the auth method via WEB-INF/context.xml (JBoss AS)
+ * @param authMethod
*/
- public void setUserName(String defaultUserName)
+ public void setAuthMethod(String authMethod)
{
- this.userName = defaultUserName;
+ this.authMethod = authMethod;
}
- /**
- * Set the password via WEB-INF/context.xml (JBoss AS)
- * @param defaultPassword
- */
- public void setPassword(String defaultPassword)
+ public void setNeedSubjectPrincipalSubstitution(String
needSubjectPrincipalSubstitutionVal)
{
- this.password = defaultPassword;
+ this.needSubjectPrincipalSubstitution =
Boolean.valueOf(needSubjectPrincipalSubstitutionVal);
}
/**
- * Set the auth method via WEB-INF/context.xml (JBoss AS)
- * @param authMethod
+ * Set this if you want to override the default {@link SubjectSecurityInteraction}
+ * @param subjectRetrieverClassName
*/
- public void setAuthMethod(String authMethod)
+ public void setSubjectInteractionClassName(String subjectRetrieverClassName)
{
- this.authMethod = authMethod;
+ this.subjectInteractionClassName = subjectRetrieverClassName;
}
@Override
- protected boolean authenticate(Request request, Response response, LoginConfig
loginConfig) throws IOException
+ public boolean authenticate(Request request, Response response, LoginConfig
loginConfig) throws IOException
{
+ log.trace("Authenticating user");
+
+ Principal principal = request.getUserPrincipal();
+ if (principal != null)
+ {
+ if (trace)
+ log.trace("Already authenticated '" + principal.getName() +
"'");
+ return true;
+ }
+
+ Session session = request.getSessionInternal(true);
+ String userName = UUID.randomUUID().toString();
+ String password = userName;
Realm realm = context.getRealm();
- Principal principal = realm.authenticate(this.userName, this.password);
+ principal = realm.authenticate(userName, password);
+ Principal originalPrincipal = principal;
if (principal != null)
{
- register(request, response, principal, this.authMethod, null, null);
+ if (needSubjectPrincipalSubstitution)
+ {
+ principal = getSubjectPrincipal();
+ if (principal == null)
+ throw new RuntimeException("Principal from subject is null");
+ principal = realm.authenticate(principal.getName(), password);
+ }
+ session.setNote(Constants.SESS_USERNAME_NOTE, principal.getName());
+ session.setNote(Constants.SESS_PASSWORD_NOTE, password);
+ request.setUserPrincipal(principal);
+ register(request, response, principal, this.authMethod, principal.getName(),
password);
+ if (originalPrincipal != null && needSubjectPrincipalSubstitution)
+ {
+ subjectInteraction.cleanup(originalPrincipal);
+ }
+ return true;
}
- return true;
+ return false;
}
+
+ public boolean authenticate(HttpServletRequest request, HttpServletResponse response,
LoginConfig loginConfig)
+ throws IOException
+ {
+ return authenticate((Request) request, (Response) response, loginConfig);
+ }
+
+ protected Principal getSubjectPrincipal()
+ {
+ if (subjectInteraction == null)
+ {
+ Class<?> clazz = SecurityActions.loadClass(getClass(),
subjectInteractionClassName);
+ try
+ {
+ subjectInteraction = (SubjectSecurityInteraction) clazz.newInstance();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ Subject subject = subjectInteraction.get();
+ if (subject != null)
+ {
+ Set<Principal> principals = subject.getPrincipals();
+ if (!principals.isEmpty())
+ {
+ return subject.getPrincipals().iterator().next();
+ }
+ }
+ return null;
+ }
}
\ No newline at end of file
Added:
federation/trunk/picketlink-bindings/src/main/java/org/picketlink/identity/federation/bindings/tomcat/SubjectSecurityInteraction.java
===================================================================
---
federation/trunk/picketlink-bindings/src/main/java/org/picketlink/identity/federation/bindings/tomcat/SubjectSecurityInteraction.java
(rev 0)
+++
federation/trunk/picketlink-bindings/src/main/java/org/picketlink/identity/federation/bindings/tomcat/SubjectSecurityInteraction.java 2011-09-13
20:10:47 UTC (rev 1220)
@@ -0,0 +1,48 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, 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.identity.federation.bindings.tomcat;
+
+import java.security.Principal;
+
+import javax.security.auth.Subject;
+
+/**
+ * Interface to retrieve a subject
+ * @author Anil.Saldhana(a)redhat.com
+ * @since Sep 13, 2011
+ */
+public interface SubjectSecurityInteraction
+{
+ /**
+ * Obtain a subject based on implementation
+ * @return
+ */
+ Subject get();
+
+ /**
+ * Clean up the {@link Principal} from
+ * the security cache
+ * @param principal
+ * @return
+ */
+ boolean cleanup(Principal principal);
+}
\ No newline at end of file
Added:
federation/trunk/picketlink-bindings-jboss/src/main/java/org/picketlink/identity/federation/bindings/jboss/subject/PicketLinkJBossSubjectInteraction.java
===================================================================
---
federation/trunk/picketlink-bindings-jboss/src/main/java/org/picketlink/identity/federation/bindings/jboss/subject/PicketLinkJBossSubjectInteraction.java
(rev 0)
+++
federation/trunk/picketlink-bindings-jboss/src/main/java/org/picketlink/identity/federation/bindings/jboss/subject/PicketLinkJBossSubjectInteraction.java 2011-09-13
20:10:47 UTC (rev 1220)
@@ -0,0 +1,106 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, 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.identity.federation.bindings.jboss.subject;
+
+import java.security.Principal;
+import java.util.Calendar;
+
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.security.auth.Subject;
+import javax.security.jacc.PolicyContext;
+import javax.security.jacc.PolicyContextException;
+
+import org.jboss.logging.Logger;
+import org.jboss.security.SimplePrincipal;
+import org.jboss.security.SubjectSecurityManager;
+import org.picketlink.identity.federation.bindings.tomcat.SubjectSecurityInteraction;
+import
org.picketlink.identity.federation.core.factories.JBossAuthCacheInvalidationFactory;
+import
org.picketlink.identity.federation.core.factories.JBossAuthCacheInvalidationFactory.TimeCacheExpiry;
+
+/**
+ * An implementation of {@link SubjectSecurityInteraction} for JBoss AS
+ * @author Anil.Saldhana(a)redhat.com
+ * @since Sep 13, 2011
+ */
+public class PicketLinkJBossSubjectInteraction implements SubjectSecurityInteraction
+{
+ protected static Logger log =
Logger.getLogger(PicketLinkJBossSubjectInteraction.class);
+
+ protected boolean trace = log.isTraceEnabled();
+
+ /**
+ * @see
org.picketlink.identity.federation.bindings.tomcat.SubjectSecurityInteraction#cleanup(java.security.Principal)
+ */
+ public boolean cleanup(Principal principal)
+ {
+ try
+ {
+ String securityDomain = getSecurityDomain();
+ if (trace)
+ {
+ log.trace("Determined Security Domain=" + securityDomain);
+ }
+ TimeCacheExpiry cacheExpiry =
JBossAuthCacheInvalidationFactory.getCacheExpiry();
+ Calendar calendar = Calendar.getInstance();
+ calendar.add(Calendar.SECOND, 10);//Add 25 seconds
+ if (trace)
+ {
+ log.trace("Will expire from cache in 10 seconds, principal=" +
principal);
+ }
+ cacheExpiry.register(securityDomain, calendar.getTime(), principal);
+ //Additional expiry of simple principal
+ cacheExpiry.register(securityDomain, calendar.getTime(), new
SimplePrincipal(principal.getName()));
+ }
+ catch (NamingException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+ return false;
+ }
+
+ /**
+ * @see
org.picketlink.identity.federation.bindings.tomcat.SubjectSecurityInteraction#get()
+ */
+ public Subject get()
+ {
+ try
+ {
+ return (Subject)
PolicyContext.getContext("javax.security.auth.Subject.container");
+ }
+ catch (PolicyContextException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private String getSecurityDomain() throws NamingException
+ {
+ //Get the SecurityManagerService from JNDI
+ InitialContext ctx = new InitialContext();
+ SubjectSecurityManager ssm = (SubjectSecurityManager)
ctx.lookup("java:comp/env/security/securityMgr");
+ if (ssm == null)
+ throw new RuntimeException("Unable to get the subject security
manager");
+ return ssm.getSecurityDomain();
+ }
+}
\ No newline at end of file