[jboss-cvs] Picketlink SVN: r296 - in federation/trunk/picketlink-bindings-jboss: src/main/java/org/picketlink/identity/federation/bindings/jboss/auth and 9 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Fri Jun 11 15:25:04 EDT 2010


Author: bmozaffa at redhat.com
Date: 2010-06-11 15:25:03 -0400 (Fri, 11 Jun 2010)
New Revision: 296

Added:
   federation/trunk/picketlink-bindings-jboss/src/main/java/org/picketlink/identity/federation/bindings/jboss/auth/mapping/
   federation/trunk/picketlink-bindings-jboss/src/main/java/org/picketlink/identity/federation/bindings/jboss/auth/mapping/STSGroupMappingProvider.java
   federation/trunk/picketlink-bindings-jboss/src/main/java/org/picketlink/identity/federation/bindings/jboss/auth/mapping/STSPrincipalMappingProvider.java
   federation/trunk/picketlink-bindings-jboss/src/test/java/org/
   federation/trunk/picketlink-bindings-jboss/src/test/java/org/picketlink/
   federation/trunk/picketlink-bindings-jboss/src/test/java/org/picketlink/identity/
   federation/trunk/picketlink-bindings-jboss/src/test/java/org/picketlink/identity/federation/
   federation/trunk/picketlink-bindings-jboss/src/test/java/org/picketlink/identity/federation/bindings/
   federation/trunk/picketlink-bindings-jboss/src/test/java/org/picketlink/identity/federation/bindings/jboss/
   federation/trunk/picketlink-bindings-jboss/src/test/java/org/picketlink/identity/federation/bindings/jboss/auth/
   federation/trunk/picketlink-bindings-jboss/src/test/java/org/picketlink/identity/federation/bindings/jboss/auth/STSMappingProviderUnitTestCase.java
Modified:
   federation/trunk/picketlink-bindings-jboss/pom.xml
Log:
PLFED-87: STS Login Modules now look for any configured principal and role mapping providers in the security domain and use them to obtain user id and role and populate the Subject with them. These two OOTB mapping providers extract and return the user's id and roles for use in a JBoss environment.

Modified: federation/trunk/picketlink-bindings-jboss/pom.xml
===================================================================
--- federation/trunk/picketlink-bindings-jboss/pom.xml	2010-06-11 19:13:30 UTC (rev 295)
+++ federation/trunk/picketlink-bindings-jboss/pom.xml	2010-06-11 19:25:03 UTC (rev 296)
@@ -81,6 +81,12 @@
          <artifactId>junit</artifactId>
          <scope>test</scope>
       </dependency>
+      <dependency>
+         <groupId>org.jboss.javaee</groupId>
+         <artifactId>jboss-javaee</artifactId>
+         <version>5.0.0.CR1</version>
+			<scope>provided</scope>
+      </dependency>
    </dependencies>
    
    <reporting>

Added: federation/trunk/picketlink-bindings-jboss/src/main/java/org/picketlink/identity/federation/bindings/jboss/auth/mapping/STSGroupMappingProvider.java
===================================================================
--- federation/trunk/picketlink-bindings-jboss/src/main/java/org/picketlink/identity/federation/bindings/jboss/auth/mapping/STSGroupMappingProvider.java	                        (rev 0)
+++ federation/trunk/picketlink-bindings-jboss/src/main/java/org/picketlink/identity/federation/bindings/jboss/auth/mapping/STSGroupMappingProvider.java	2010-06-11 19:25:03 UTC (rev 296)
@@ -0,0 +1,186 @@
+package org.picketlink.identity.federation.bindings.jboss.auth.mapping;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.bind.JAXBException;
+
+import org.apache.log4j.Logger;
+import org.jboss.security.identity.RoleGroup;
+import org.jboss.security.identity.plugins.SimpleRole;
+import org.jboss.security.identity.plugins.SimpleRoleGroup;
+import org.jboss.security.mapping.MappingProvider;
+import org.jboss.security.mapping.MappingResult;
+import org.picketlink.identity.federation.bindings.jboss.auth.SAML20TokenRoleAttributeProvider;
+import org.picketlink.identity.federation.core.wstrust.auth.AbstractSTSLoginModule;
+import org.picketlink.identity.federation.core.wstrust.plugins.saml.SAMLUtil;
+import org.picketlink.identity.federation.saml.v2.assertion.AssertionType;
+import org.picketlink.identity.federation.saml.v2.assertion.AttributeStatementType;
+import org.picketlink.identity.federation.saml.v2.assertion.AttributeType;
+import org.picketlink.identity.federation.saml.v2.assertion.StatementAbstractType;
+import org.w3c.dom.Element;
+
+/**
+ * <p>
+ * This mapping provider looks at the role attributes in the Assertion and
+ *  returns corresponding JBoss RoleGroup objects for insertion into the Subject.
+ * </p>
+ * 
+ * <h3>Configuration</h3>
+ * <pre>{@code
+ * <application-policy name="saml-issue-token">
+ *   <authentication>
+ *     <login-module code="org.picketlink.identity.federation.core.wstrust.auth.STSIssuingLoginModule" flag="required">
+ *       <module-option name="configFile">/sts-client.properties</module-option>
+ *       <module-option name="password-stacking">useFirstPass</module-option>
+ *     </login-module>
+ *   </authentication>
+ *   <mapping>
+ *     <mapping-module code="org.picketlink.identity.federation.bindings.jboss.auth.mapping.STSPrincipalMappingProvider" type="principal"/>
+ *     <mapping-module code="org.picketlink.identity.federation.bindings.jboss.auth.mapping.STSGroupMappingProvider" type="role">
+ *       <module-option name="token-role-attribute-name">role</module-option>
+ *     </mapping-module>
+ *   </mapping>
+ * </application-policy>
+ * }
+ * </pre>
+ * 
+ * As demonstrated above, this mapping provider is typically configured for an STS Login Module to extract user roles
+ * from the STS token and supply them for insertion into the JAAS Subject.
+ * 
+ * This mapping provider looks for a multi-valued Attribute in the Assertion, where each value is a user role.
+ * The name of this attribute defaults to {@code SAML20TokenRoleAttributeProvider.DEFAULT_TOKEN_ROLE_ATTRIBUTE_NAME} but
+ * may be set to any value through the "token-role-attribute-name" module option.
+ * <p/>
+ * 
+ * 
+ * @author <a href="mailto:Babak at redhat.com">Babak Mozaffari</a>
+ */
+public class STSGroupMappingProvider implements MappingProvider<RoleGroup>
+{
+   private Logger log = Logger.getLogger(STSGroupMappingProvider.class);
+
+   private MappingResult<RoleGroup> result;
+
+   private String tokenRoleAttributeName;
+
+   @Override
+   public void init(Map<String, Object> contextMap)
+   {
+      Object tokenRoleAttributeObject = contextMap.get("token-role-attribute-name");
+      if (tokenRoleAttributeObject != null)
+      {
+         tokenRoleAttributeName = (String) tokenRoleAttributeObject;
+      }
+      else
+      {
+         tokenRoleAttributeName = SAML20TokenRoleAttributeProvider.DEFAULT_TOKEN_ROLE_ATTRIBUTE_NAME;
+      }
+
+      //No initialization needed
+      if (log.isDebugEnabled())
+      {
+         log.debug("Initialized with " + contextMap);
+      }
+   }
+
+   @Override
+   public void performMapping(Map<String, Object> contextMap, RoleGroup Group)
+   {
+      if (log.isDebugEnabled())
+      {
+         log.debug("performMapping with map as " + contextMap);
+      }
+      if (contextMap == null)
+      {
+         throw new IllegalArgumentException(
+               "Empty context map. SAML Token must be provided in the context map to extract a Principal");
+      }
+
+      Object tokenObject = contextMap.get(AbstractSTSLoginModule.SHARED_TOKEN);
+      if (!(tokenObject instanceof Element))
+      {
+         throw new IllegalArgumentException("Did not find a token " + Element.class.getClass().getName() + " under "
+               + AbstractSTSLoginModule.SHARED_TOKEN + " in the map");
+      }
+
+      try
+      {
+         Element tokenElement = (Element) tokenObject;
+         AssertionType assertion = SAMLUtil.fromElement(tokenElement);
+
+         // check the assertion statements and look for role attributes.
+         AttributeStatementType attributeStatement = this.getAttributeStatement(assertion);
+         if (attributeStatement != null)
+         {
+            RoleGroup rolesGroup = new SimpleRoleGroup(SAML20TokenRoleAttributeProvider.JBOSS_ROLE_PRINCIPAL_NAME);
+            List<Object> attributeList = attributeStatement.getAttributeOrEncryptedAttribute();
+            for (Object obj : attributeList)
+            {
+               if (obj instanceof AttributeType)
+               {
+                  AttributeType attribute = (AttributeType) obj;
+                  // if this is a role attribute, get its values and add them to the role set.
+                  if (tokenRoleAttributeName.equals(attribute.getName()))
+                  {
+                     for (Object value : attribute.getAttributeValue())
+                     {
+                        rolesGroup.addRole(new SimpleRole((String) value));
+                     }
+                  }
+               }
+            }
+            result.setMappedObject(rolesGroup);
+            if (log.isDebugEnabled())
+            {
+               log.debug("Mapped roles to " + rolesGroup);
+            }
+         }
+      }
+      catch (JAXBException e)
+      {
+         throw new IllegalArgumentException(e);
+      }
+   }
+
+   @Override
+   public void setMappingResult(MappingResult<RoleGroup> mappingResult)
+   {
+      this.result = mappingResult;
+   }
+
+   /**
+    * @see MappingProvider#supports(Class)
+    */
+   public boolean supports(Class<?> p)
+   {
+      if (RoleGroup.class.isAssignableFrom(p))
+         return true;
+
+      return false;
+   }
+
+   /**
+    * <p>
+    * Checks if the specified SAML assertion contains a {@code AttributeStatementType} and returns this type when it
+    * is available.
+    * </p>
+    * 
+    * @param assertion a reference to the {@code AssertionType} that may contain an {@code AttributeStatementType}.
+    * @return the assertion's {@code AttributeStatementType}, or {@code null} if no such type can be found in the SAML
+    * assertion.
+    */
+   private AttributeStatementType getAttributeStatement(AssertionType assertion)
+   {
+      List<StatementAbstractType> statementList = assertion.getStatementOrAuthnStatementOrAuthzDecisionStatement();
+      if (statementList.size() != 0)
+      {
+         for (StatementAbstractType statement : statementList)
+         {
+            if (statement instanceof AttributeStatementType)
+               return (AttributeStatementType) statement;
+         }
+      }
+      return null;
+   }
+}

Added: federation/trunk/picketlink-bindings-jboss/src/main/java/org/picketlink/identity/federation/bindings/jboss/auth/mapping/STSPrincipalMappingProvider.java
===================================================================
--- federation/trunk/picketlink-bindings-jboss/src/main/java/org/picketlink/identity/federation/bindings/jboss/auth/mapping/STSPrincipalMappingProvider.java	                        (rev 0)
+++ federation/trunk/picketlink-bindings-jboss/src/main/java/org/picketlink/identity/federation/bindings/jboss/auth/mapping/STSPrincipalMappingProvider.java	2010-06-11 19:25:03 UTC (rev 296)
@@ -0,0 +1,107 @@
+package org.picketlink.identity.federation.bindings.jboss.auth.mapping;
+
+import java.security.Principal;
+import java.util.Map;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+
+import org.apache.log4j.Logger;
+import org.jboss.security.SimplePrincipal;
+import org.jboss.security.mapping.MappingResult;
+import org.jboss.security.mapping.providers.principal.AbstractPrincipalMappingProvider;
+import org.picketlink.identity.federation.core.wstrust.auth.AbstractSTSLoginModule;
+import org.picketlink.identity.federation.core.wstrust.plugins.saml.SAMLUtil;
+import org.picketlink.identity.federation.saml.v2.assertion.AssertionType;
+import org.picketlink.identity.federation.saml.v2.assertion.NameIDType;
+import org.picketlink.identity.federation.saml.v2.assertion.SubjectType;
+import org.w3c.dom.Element;
+
+/**
+ * <p>
+ * This mapping provider looks at the NameID in the Assertion and
+ *  returns a corresponding JBoss Principal for insertion into the Subject.
+ * </p>
+ * 
+ * <h3>Configuration</h3>
+ * <pre>{@code
+ * <application-policy name="saml-issue-token">
+ *   <authentication>
+ *     <login-module code="org.picketlink.identity.federation.core.wstrust.auth.STSIssuingLoginModule" flag="required">
+ *       <module-option name="configFile">/sts-client.properties</module-option>
+ *       <module-option name="password-stacking">useFirstPass</module-option>
+ *     </login-module>
+ *   </authentication>
+ *   <mapping>
+ *     <mapping-module code="org.picketlink.identity.federation.bindings.jboss.auth.mapping.STSPrincipalMappingProvider" type="principal"/>
+ *     <mapping-module code="org.picketlink.identity.federation.bindings.jboss.auth.mapping.STSGroupMappingProvider" type="role"/>
+ *   </mapping>
+ * </application-policy>
+ * }
+ * </pre>
+ * 
+ * @author <a href="mailto:Babak at redhat.com">Babak Mozaffari</a>
+ */
+public class STSPrincipalMappingProvider extends AbstractPrincipalMappingProvider
+{
+   private Logger log = Logger.getLogger(STSPrincipalMappingProvider.class);
+
+   private MappingResult<Principal> result;
+
+   @Override
+   public void init(Map<String, Object> contextMap)
+   {
+      //No initialization needed
+   }
+
+   @Override
+   public void performMapping(Map<String, Object> contextMap, Principal principal)
+   {
+      if (contextMap == null)
+      {
+         throw new IllegalArgumentException(
+               "Empty context map. SAML Token must be provided in the context map to extract a Principal");
+      }
+
+      Object tokenObject = contextMap.get(AbstractSTSLoginModule.SHARED_TOKEN);
+      if (!(tokenObject instanceof Element))
+      {
+         throw new IllegalArgumentException("Did not find a token " + Element.class.getClass().getName() + " under "
+               + AbstractSTSLoginModule.SHARED_TOKEN + " in the map");
+      }
+
+      try
+      {
+         Element tokenElement = (Element) tokenObject;
+         AssertionType assertion = SAMLUtil.fromElement(tokenElement);
+         SubjectType subject = assertion.getSubject();
+         if (subject != null)
+         {
+            for (JAXBElement<?> element : subject.getContent())
+            {
+               if (element.getDeclaredType().equals(NameIDType.class))
+               {
+                  NameIDType nameID = (NameIDType) element.getValue();
+                  Principal mappedPrincipal = new SimplePrincipal(nameID.getValue());
+                  result.setMappedObject(mappedPrincipal);
+                  if (log.isDebugEnabled())
+                  {
+                     log.debug("Mapped principal to " + mappedPrincipal);
+                  }
+                  return;
+               }
+            }
+         }
+      }
+      catch (JAXBException e)
+      {
+         throw new IllegalArgumentException(e);
+      }
+   }
+
+   @Override
+   public void setMappingResult(MappingResult<Principal> mappingResult)
+   {
+      this.result = mappingResult;
+   }
+}

Added: federation/trunk/picketlink-bindings-jboss/src/test/java/org/picketlink/identity/federation/bindings/jboss/auth/STSMappingProviderUnitTestCase.java
===================================================================
--- federation/trunk/picketlink-bindings-jboss/src/test/java/org/picketlink/identity/federation/bindings/jboss/auth/STSMappingProviderUnitTestCase.java	                        (rev 0)
+++ federation/trunk/picketlink-bindings-jboss/src/test/java/org/picketlink/identity/federation/bindings/jboss/auth/STSMappingProviderUnitTestCase.java	2010-06-11 19:25:03 UTC (rev 296)
@@ -0,0 +1,138 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, 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.auth;
+
+import java.security.Principal;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.namespace.QName;
+
+import junit.framework.TestCase;
+
+import org.jboss.security.identity.RoleGroup;
+import org.jboss.security.mapping.MappingProvider;
+import org.jboss.security.mapping.MappingResult;
+import org.picketlink.identity.federation.bindings.jboss.auth.mapping.STSGroupMappingProvider;
+import org.picketlink.identity.federation.bindings.jboss.auth.mapping.STSPrincipalMappingProvider;
+import org.picketlink.identity.federation.core.wstrust.WSTrustConstants;
+import org.picketlink.identity.federation.core.wstrust.auth.AbstractSTSLoginModule;
+import org.picketlink.identity.federation.core.wstrust.plugins.saml.SAMLUtil;
+import org.picketlink.identity.federation.saml.v2.assertion.AssertionType;
+import org.picketlink.identity.federation.saml.v2.assertion.AttributeStatementType;
+import org.picketlink.identity.federation.saml.v2.assertion.AttributeType;
+import org.picketlink.identity.federation.saml.v2.assertion.NameIDType;
+import org.picketlink.identity.federation.saml.v2.assertion.SubjectType;
+import org.w3c.dom.Element;
+
+/**
+ * <p>
+ * This {@code TestCase} tests the functionalities of {@code STSPrincipalMappingProvider} and {@code STSGroupMappingProvider}.
+ * </p>
+ * 
+ * @author <a href="mailto:Babak at redhat.com">Babak Mozaffari</a>
+ */
+public class STSMappingProviderUnitTestCase extends TestCase
+{
+
+   @Override
+   protected void setUp() throws Exception
+   {
+      super.setUp();
+   }
+
+   /**
+    * <p>
+    * Tests that {@code STSGroupMappingProvider} correctly maps and returns a {@code RoleGroup}
+    * </p>
+    * 
+    * @throws Exception if an error occurs while running the test.
+    */
+   public void testSTSGroupMappingProvider() throws Exception
+   {
+      String roleAttributeName = "roleAttributeName";
+      String role1 = "userRole1";
+      String role2 = "userRole2";
+      
+      AssertionType assertion = new AssertionType();
+      AttributeStatementType attributeStatementType = new AttributeStatementType();
+      assertion.getStatementOrAuthnStatementOrAuthzDecisionStatement().add(attributeStatementType);
+      AttributeType attributeType = new AttributeType();
+      attributeStatementType.getAttributeOrEncryptedAttribute().add(attributeType);
+      attributeType.setName(roleAttributeName);
+      attributeType.getAttributeValue().add(role1);
+      attributeType.getAttributeValue().add(role2);
+      
+      MappingResult<RoleGroup> mappingResult = new MappingResult<RoleGroup>();
+      Map<String, Object> contextMap = new HashMap<String, Object>();
+      contextMap.put("token-role-attribute-name", roleAttributeName);
+      contextMap.put(AbstractSTSLoginModule.SHARED_TOKEN, SAMLUtil.toElement(assertion));
+      
+      MappingProvider<RoleGroup> mappingProvider = new STSGroupMappingProvider();
+      mappingProvider.init(contextMap);
+      mappingProvider.setMappingResult(mappingResult);
+      mappingProvider.performMapping(contextMap, null);
+
+      RoleGroup roleGroup = mappingResult.getMappedObject();
+      assertNotNull("Unexpected null mapped role", roleGroup);
+      assertEquals("RoleGroup name has unexpected value", SAML20TokenRoleAttributeProvider.JBOSS_ROLE_PRINCIPAL_NAME, roleGroup.getRoleName());
+      assertEquals("RoleGroup has unexpected first role", role1, roleGroup.getRoles().get(0).getRoleName());
+      assertEquals("RoleGroup has unexpected second role", role2, roleGroup.getRoles().get(1).getRoleName());
+   }
+
+   /**
+    * <p>
+    * Tests that {@code STSPrincipalMappingProvider} correctly maps and returns a {@code Principal}
+    * </p>
+    * 
+    * @throws Exception if an error occurs while running the test.
+    */
+   public void testSTSPrincipalMappingProvider() throws Exception
+   {
+      String userId = "babak";
+      
+      AssertionType assertion = new AssertionType();
+      SubjectType subjectType = new SubjectType();
+      assertion.setSubject(subjectType);
+      QName name = new QName(WSTrustConstants.SAML2_ASSERTION_NS, "NameID");
+      Class<NameIDType> declaredType = NameIDType.class;
+      NameIDType nameIDType = new NameIDType();
+      nameIDType.setValue(userId);
+      JAXBElement<NameIDType> jaxbElement = new JAXBElement<NameIDType>(name, declaredType, JAXBElement.GlobalScope.class, nameIDType);
+      subjectType.getContent().add(jaxbElement);
+      
+      MappingResult<Principal> mappingResult = new MappingResult<Principal>();
+      Map<String, Object> contextMap = new HashMap<String, Object>();
+      Element assertionElement = SAMLUtil.toElement(assertion);
+      contextMap.put(AbstractSTSLoginModule.SHARED_TOKEN, assertionElement);
+      
+      MappingProvider<Principal> mappingProvider = new STSPrincipalMappingProvider();
+      mappingProvider.init(contextMap);
+      mappingProvider.setMappingResult(mappingResult);
+      mappingProvider.performMapping(contextMap, null);
+
+      Principal principal = mappingResult.getMappedObject();
+      assertNotNull("Unexpected null mapped principal", principal);
+      assertEquals("Principal has unexpected value", userId, principal.getName());
+   }
+}



More information about the jboss-cvs-commits mailing list