You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by ow...@apache.org on 2013/05/04 00:11:03 UTC

svn commit: r1478989 - in /cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims: LdapGroupClaimsHandler.java LdapUtils.java

Author: owulff
Date: Fri May  3 22:11:02 2013
New Revision: 1478989

URL: http://svn.apache.org/r1478989
Log:
[CXF-4994] Support LDAP groups as claim

Added:
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapGroupClaimsHandler.java
Modified:
    cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapUtils.java

Added: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapGroupClaimsHandler.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapGroupClaimsHandler.java?rev=1478989&view=auto
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapGroupClaimsHandler.java (added)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapGroupClaimsHandler.java Fri May  3 22:11:02 2013
@@ -0,0 +1,281 @@
+/**
+ * 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.cxf.sts.claims;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.regex.Pattern;
+
+import javax.naming.Name;
+import javax.security.auth.kerberos.KerberosPrincipal;
+import javax.security.auth.x500.X500Principal;
+
+import org.apache.cxf.common.logging.LogUtils;
+import org.springframework.ldap.core.LdapTemplate;
+
+public class LdapGroupClaimsHandler implements ClaimsHandler {
+
+    private static final Logger LOG = LogUtils.getL7dLogger(LdapGroupClaimsHandler.class);
+
+    private static final String SCOPE = "%SCOPE%";
+    private static final String ROLE = "%ROLE%";
+    
+    private LdapTemplate ldap;
+    private String userBaseDn;
+    private String groupBaseDn;
+    private String userObjectClass = "person";
+    private String groupObjectClass = "groupOfNames";
+    private String userNameAttribute = "cn";
+    private String groupMemberAttribute = "member";
+    private String groupURI = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role";
+    private String groupNameGlobalFilter = ROLE;
+    private String groupNameScopedFilter = SCOPE + "_" + ROLE;
+    private Map<String, String> appliesToScopeMapping;
+    
+    
+    public String getUserObjectClass() {
+        return userObjectClass;
+    }
+
+    public void setUserObjectClass(String userObjectClass) {
+        this.userObjectClass = userObjectClass;
+    }
+    
+    public String getGroupObjectClass() {
+        return groupObjectClass;
+    }
+
+    public void setGroupObjectClass(String groupObjectClass) {
+        this.groupObjectClass = groupObjectClass;
+    }
+
+    public String getUserNameAttribute() {
+        return userNameAttribute;
+    }
+
+    public void setUserNameAttribute(String userNameAttribute) {
+        this.userNameAttribute = userNameAttribute;
+    }
+
+    public void setLdapTemplate(LdapTemplate ldapTemplate) {
+        this.ldap = ldapTemplate;
+    }
+
+    public LdapTemplate getLdapTemplate() {
+        return ldap;
+    }
+
+    public void setUserBaseDN(String userBaseDN) {
+        this.userBaseDn = userBaseDN;
+    }
+
+    public String getUserBaseDN() {
+        return userBaseDn;
+    }
+    
+    public String getGroupMemberAttribute() {
+        return groupMemberAttribute;
+    }
+
+    public void setGroupMemberAttribute(String groupMemberAttribute) {
+        this.groupMemberAttribute = groupMemberAttribute;
+    }
+
+    public String getGroupURI() {
+        return groupURI;
+    }
+
+    public void setGroupURI(String groupURI) {
+        this.groupURI = groupURI;
+    }
+    
+    public void setAppliesToScopeMapping(Map<String, String> appliesToScopeMapping) {
+        this.appliesToScopeMapping = appliesToScopeMapping;
+    }
+
+    public Map<String, String> getAppliesToScopeMapping() {
+        return appliesToScopeMapping;
+    }
+    
+    public String getGroupBaseDN() {
+        return groupBaseDn;
+    }
+
+    public void setGroupBaseDN(String groupBaseDN) {
+        this.groupBaseDn = groupBaseDN;
+    }
+
+    public String getGroupNameGlobalFilter() {
+        return groupNameGlobalFilter;
+    }
+
+    public void setGroupNameGlobalFilter(String groupNameGlobalFilter) {
+        this.groupNameGlobalFilter = groupNameGlobalFilter;
+    }
+
+    public String getGroupNameScopedFilter() {
+        return groupNameScopedFilter;
+    }
+
+    public void setGroupNameScopedFilter(String groupNameScopedFilter) {
+        this.groupNameScopedFilter = groupNameScopedFilter;
+    }
+    
+    public List<URI> getSupportedClaimTypes() {
+        List<URI> list = new ArrayList<URI>();
+        try {
+            list.add(new URI(this.groupURI));
+        } catch (URISyntaxException e) {
+            LOG.warning("Invalid groupURI '" + this.groupURI + "'");
+        }
+        return list;
+    }    
+    
+    public ClaimCollection retrieveClaimValues(
+            RequestClaimCollection claims, ClaimsParameters parameters) {
+        
+        boolean found = false;
+        for (RequestClaim claim: claims) {
+            if (claim.getClaimType().toString().equals(this.groupURI)) {
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            return new ClaimCollection();
+        }
+        
+        String user = null;
+        
+        Principal principal = parameters.getPrincipal();
+        if (principal instanceof KerberosPrincipal) {
+            KerberosPrincipal kp = (KerberosPrincipal)principal;
+            StringTokenizer st = new StringTokenizer(kp.getName(), "@");
+            user = st.nextToken();
+        } else if (principal instanceof X500Principal) {
+            X500Principal x500p = (X500Principal)principal;
+            LOG.warning("Unsupported principal type X500: " + x500p.getName());
+        } else if (principal != null) {
+            user = principal.getName();
+            if (user == null) {
+                LOG.warning("Principal name must not be null");
+            }
+        } else {
+            LOG.warning("Principal is null");
+        }
+        if (user == null) {
+            return new ClaimCollection();
+        }
+        
+        if (!LdapUtils.isDN(user)) {
+            Name dn = LdapUtils.getDnOfEntry(ldap, this.userBaseDn, this.getUserObjectClass(),
+                                             this.getUserNameAttribute(), user);
+            if (dn != null) {
+                user = dn.toString();
+                LOG.fine("DN for (" + this.getUserNameAttribute() + "=" + user + ") found: " + user);
+            } else {
+                LOG.warning("DN not found for user '" + user + "'");
+                return new ClaimCollection();
+            }
+        }
+        
+        if (LOG.isLoggable(Level.FINER)) {
+            LOG.finest("Retrieve groups for user " + user);
+        }
+        
+        List<String> groups = null;
+        groups = LdapUtils.getAttributeOfEntries(ldap, this.groupBaseDn, this.getGroupObjectClass(),
+                                                            this.groupMemberAttribute, user, "cn");
+        
+        if (groups == null || groups.size() == 0) {
+            if (LOG.isLoggable(Level.INFO)) {
+                LOG.finest("No groups found for user '" + user + "'");
+            }
+            return new ClaimCollection();
+        }
+        
+        String scope = null;
+        if (getAppliesToScopeMapping() != null && getAppliesToScopeMapping().size() > 0
+            && parameters.getAppliesToAddress() != null) {
+            scope = getAppliesToScopeMapping().get(parameters.getAppliesToAddress());
+        }
+        
+        String regex = this.groupNameGlobalFilter;
+        regex = regex.replaceAll(ROLE, ".*");
+        Pattern globalPattern = Pattern.compile(regex);
+        
+        //If AppliesTo value can be mapped to a Scope Name
+        //ex. https://localhost/doubleit/services/doubleittransport  -> Demo
+        Pattern scopePattern = null;
+        if (scope != null) {
+            regex = this.groupNameScopedFilter;
+            regex = regex.replaceAll(SCOPE, scope).replaceAll(ROLE, ".*");
+            scopePattern = Pattern.compile(regex);
+        }
+        
+        List<String> filteredGroups = new ArrayList<String>();
+        for (String group: groups) {
+            if (scopePattern != null && scopePattern.matcher(group).matches()) {
+                //Group matches the scoped filter
+                //ex. (default groupNameScopeFilter)
+                //  Demo_User -> Role=User
+                //  Demo_Admin -> Role=Admin
+                String filter = this.groupNameScopedFilter;
+                filteredGroups.add(parseRole(group, filter.replaceAll(SCOPE, scope)));
+            } else {
+                if (globalPattern.matcher(group).matches()) {
+                    //Group matches the global filter
+                    //ex. (default groupNameGlobalFilter)
+                    //  User -> Role=User
+                    //  Admin -> Role=Admin
+                    filteredGroups.add(parseRole(group, this.groupNameGlobalFilter));
+                } else {
+                    LOG.finer("Group '" + group + "' doesn't match scoped and global group filter");
+                }
+            }
+        }
+        
+        ClaimCollection claimsColl = new ClaimCollection();
+        Claim c = new Claim();
+        c.setClaimType(URI.create(this.groupURI));
+        c.setPrincipal(principal);
+        c.setValues(filteredGroups);
+        // c.setIssuer(issuer);
+        // c.setOriginalIssuer(originalIssuer);
+        // c.setNamespace(namespace);
+        claimsColl.add(c);
+
+        return claimsColl;
+    }
+
+    private String parseRole(String group, String filter) {
+        int roleStart = filter.indexOf(ROLE);
+        int trimEnd = filter.length() - ROLE.length() - roleStart;
+        return group.substring(roleStart, group.length() - trimEnd);
+    }
+    
+}
+

Modified: cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapUtils.java
URL: http://svn.apache.org/viewvc/cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapUtils.java?rev=1478989&r1=1478988&r2=1478989&view=diff
==============================================================================
--- cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapUtils.java (original)
+++ cxf/trunk/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapUtils.java Fri May  3 22:11:02 2013
@@ -22,6 +22,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
+import javax.naming.Name;
 import javax.naming.NamingEnumeration;
 import javax.naming.NamingException;
 import javax.naming.directory.Attribute;
@@ -32,7 +33,10 @@ import javax.security.auth.x500.X500Prin
 import org.apache.cxf.helpers.CastUtils;
 
 import org.springframework.ldap.core.AttributesMapper;
+import org.springframework.ldap.core.ContextMapper;
+import org.springframework.ldap.core.DirContextOperations;
 import org.springframework.ldap.core.LdapTemplate;
+import org.springframework.ldap.core.support.AbstractContextMapper;
 import org.springframework.ldap.filter.AndFilter;
 import org.springframework.ldap.filter.EqualsFilter;
 
@@ -80,10 +84,70 @@ public final class LdapUtils {
         result = ldapTemplate.search((baseDN == null) ? "" : baseDN, filter.toString(),
             SearchControls.SUBTREE_SCOPE, searchAttributes, mapper);
         if (result != null && result.size() > 0) {
-            //not only the first one....
             ldapAttributes = CastUtils.cast((Map<?, ?>)result.get(0));
         }
         
         return ldapAttributes;
     }
+    
+    public static List<String> getAttributeOfEntries(
+        LdapTemplate ldapTemplate, String baseDN, 
+        String objectClass, String filterAttributeName, String filterAttributeValue,
+        String searchAttribute) {
+
+        List<String> ldapAttributes = null;
+
+        AttributesMapper mapper = 
+            new AttributesMapper() {
+                public Object mapFromAttributes(Attributes attrs) throws NamingException {
+                    NamingEnumeration<? extends Attribute> attrEnum = attrs.getAll();
+                    while (attrEnum.hasMore()) {
+                        return (String) attrEnum.next().get();
+                    }
+                    return null;
+                }
+            };
+        
+        String[] searchAttributes = new String[] {searchAttribute};  
+        
+        List<?> result = null;
+        AndFilter filter = new AndFilter();
+        filter.and(
+            new EqualsFilter("objectclass", objectClass)).and(
+                new EqualsFilter(filterAttributeName, filterAttributeValue));
+
+        result = ldapTemplate.search((baseDN == null) ? "" : baseDN, filter.toString(),
+            SearchControls.SUBTREE_SCOPE, searchAttributes, mapper);
+        if (result != null && result.size() > 0) {
+            ldapAttributes = CastUtils.cast((List<?>)result);
+        }
+
+        return ldapAttributes;
+    }
+    
+    public static Name getDnOfEntry(LdapTemplate ldapTemplate, String baseDN, 
+        String objectClass, String filterAttributeName, String filterAttributeValue) {
+
+        ContextMapper mapper = 
+            new AbstractContextMapper() {
+                public Object doMapFromContext(DirContextOperations ctx) {
+                    return ctx.getDn();
+                }
+            };
+        
+        AndFilter filter = new AndFilter();
+        filter.and(
+            new EqualsFilter("objectclass", objectClass)).and(
+                new EqualsFilter(filterAttributeName, filterAttributeValue));
+
+        List<?> result = ldapTemplate.search((baseDN == null) ? "" : baseDN, filter.toString(),
+            SearchControls.SUBTREE_SCOPE, mapper);
+        
+        if (result != null && result.size() > 0) {
+            //not only the first one....
+            return (Name)result.get(0);
+        }
+        return null;
+    }
+    
 }