You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by dk...@apache.org on 2013/05/04 03:12:45 UTC
svn commit: r1479023 - in
/cxf/branches/2.7.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims:
LdapGroupClaimsHandler.java LdapUtils.java
Author: dkulp
Date: Sat May 4 01:12:45 2013
New Revision: 1479023
URL: http://svn.apache.org/r1479023
Log:
Merged revisions 1478989 via git cherry-pick from
https://svn.apache.org/repos/asf/cxf/trunk
........
r1478989 | owulff | 2013-05-03 18:11:02 -0400 (Fri, 03 May 2013) | 2 lines
[CXF-4994] Support LDAP groups as claim
........
Added:
cxf/branches/2.7.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapGroupClaimsHandler.java
Modified:
cxf/branches/2.7.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapUtils.java
Added: cxf/branches/2.7.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapGroupClaimsHandler.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.7.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapGroupClaimsHandler.java?rev=1479023&view=auto
==============================================================================
--- cxf/branches/2.7.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapGroupClaimsHandler.java (added)
+++ cxf/branches/2.7.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapGroupClaimsHandler.java Sat May 4 01:12:45 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/branches/2.7.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapUtils.java
URL: http://svn.apache.org/viewvc/cxf/branches/2.7.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapUtils.java?rev=1479023&r1=1479022&r2=1479023&view=diff
==============================================================================
--- cxf/branches/2.7.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapUtils.java (original)
+++ cxf/branches/2.7.x-fixes/services/sts/sts-core/src/main/java/org/apache/cxf/sts/claims/LdapUtils.java Sat May 4 01:12:45 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;
+ }
+
}