/**
* Copyright (c) Codice Foundation
* <p>
* 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 3 of the
* License, or any later version.
* <p>
* This program 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. A copy of the GNU Lesser General Public License
* is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
*/
package ddf.security.sts.claimsHandler;
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 org.apache.cxf.rt.security.claims.ClaimCollection;
import org.apache.cxf.sts.claims.ClaimsHandler;
import org.apache.cxf.sts.claims.ClaimsParameters;
import org.apache.cxf.sts.claims.ProcessedClaim;
import org.apache.cxf.sts.claims.ProcessedClaimCollection;
import org.forgerock.opendj.ldap.Attribute;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.LDAPConnectionFactory;
import org.forgerock.opendj.ldap.LdapException;
import org.forgerock.opendj.ldap.SearchResultReferenceIOException;
import org.forgerock.opendj.ldap.SearchScope;
import org.forgerock.opendj.ldap.requests.BindRequest;
import org.forgerock.opendj.ldap.responses.BindResult;
import org.forgerock.opendj.ldap.responses.SearchResultEntry;
import org.forgerock.opendj.ldif.ConnectionEntryReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
public class RoleClaimsHandler implements ClaimsHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(RoleClaimsHandler.class);
private boolean overrideCertDn = false;
private Map<String, String> claimsLdapAttributeMapping;
private LDAPConnectionFactory connectionFactory;
private String delimiter = ";";
private String objectClass = "groupOfNames";
private String memberNameAttribute = "member";
private String membershipUserAttribute = "uid";
private String loginUserAttribute = "uid";
private String groupNameAttribute = "cn";
private String userBaseDn;
private String groupBaseDn;
private String roleClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/role";
private String propertyFileLocation;
private String bindUserCredentials;
private String bindUserDN;
private String bindMethod;
private String kerberosRealm;
private String kdcAddress;
public URI getRoleURI() {
URI uri = null;
try {
uri = new URI(roleClaimType);
} catch (URISyntaxException e) {
LOGGER.info(
"Unable to add role claim type. Set log level for \"ddf.security.sts.claimsHandler\" to DEBUG for more information.");
LOGGER.debug("Unable to add role claim type.", e);
}
return uri;
}
public String getPropertyFileLocation() {
return propertyFileLocation;
}
public void setPropertyFileLocation(String propertyFileLocation) {
if (propertyFileLocation != null && !propertyFileLocation.isEmpty()
&& !propertyFileLocation.equals(this.propertyFileLocation)) {
setClaimsLdapAttributeMapping(AttributeMapLoader.buildClaimsMapFile(propertyFileLocation));
}
this.propertyFileLocation = propertyFileLocation;
}
public String getRoleClaimType() {
return roleClaimType;
}
public void setRoleClaimType(String roleClaimType) {
this.roleClaimType = roleClaimType;
}
public String getGroupNameAttribute() {
return groupNameAttribute;
}
public void setGroupNameAttribute(String groupNameAttribute) {
this.groupNameAttribute = groupNameAttribute;
}
public String getDelimiter() {
return delimiter;
}
public void setDelimiter(String delimiter) {
this.delimiter = delimiter;
}
public String getGroupBaseDn() {
return groupBaseDn;
}
public void setGroupBaseDn(String groupBaseDn) {
this.groupBaseDn = groupBaseDn;
}
public LDAPConnectionFactory getLdapConnectionFactory() {
return connectionFactory;
}
public void setLdapConnectionFactory(LDAPConnectionFactory connection) {
this.connectionFactory = connection;
}
public String getMembershipUserAttribute() {
return membershipUserAttribute;
}
public void setMembershipUserAttribute(String membershipUserAttribute) {
this.membershipUserAttribute = membershipUserAttribute;
}
public String getLoginUserAttribute() {
return loginUserAttribute;
}
public void setLoginUserAttribute(String loginUserAttribute) {
this.loginUserAttribute = loginUserAttribute;
}
public String getObjectClass() {
return objectClass;
}
public void setObjectClass(String objectClass) {
this.objectClass = objectClass;
}
public String getMemberNameAttribute() {
return memberNameAttribute;
}
public void setMemberNameAttribute(String memberNameAttribute) {
this.memberNameAttribute = memberNameAttribute;
}
public String getUserBaseDn() {
return userBaseDn;
}
public void setUserBaseDn(String userBaseDn) {
this.userBaseDn = userBaseDn;
}
public void setBindMethod(String bindMethod) {
this.bindMethod = bindMethod;
}
public void setKerberosRealm(String kerberosRealm) {
this.kerberosRealm = kerberosRealm;
}
public void setKdcAddress(String kdcAddress) {
this.kdcAddress = kdcAddress;
}
public Map<String, String> getClaimsLdapAttributeMapping() {
return claimsLdapAttributeMapping;
}
public void setClaimsLdapAttributeMapping(Map<String, String> ldapClaimMapping) {
this.claimsLdapAttributeMapping = ldapClaimMapping;
}
@Override
public List<URI> getSupportedClaimTypes() {
List<URI> uriList = new ArrayList<>();
uriList.add(getRoleURI());
return uriList;
}
@Override
public ProcessedClaimCollection retrieveClaimValues(ClaimCollection claims,
ClaimsParameters parameters) {
String[] attributes = {groupNameAttribute, memberNameAttribute};
ProcessedClaimCollection claimsColl = new ProcessedClaimCollection();
Connection connection = null;
try {
Principal principal = parameters.getPrincipal();
String user = AttributeMapLoader.getUser(principal);
if (user == null) {
LOGGER.info(
"Could not determine user name, possible authentication error. Returning no claims.");
return new ProcessedClaimCollection();
}
connection = connectionFactory.getConnection();
if (connection != null) {
BindRequest request = BindMethodChooser.selectBindMethod(bindMethod,
bindUserDN,
bindUserCredentials,
kerberosRealm,
kdcAddress);
BindResult bindResult = connection.bind(request);
String membershipValue = user;
AndFilter filter;
ConnectionEntryReader entryReader;
if (!membershipUserAttribute.equals(loginUserAttribute)) {
String baseDN = AttributeMapLoader.getBaseDN(principal,
userBaseDn,
overrideCertDn);
filter = new AndFilter();
filter.and(new EqualsFilter(this.getLoginUserAttribute(), user));
entryReader = connection.search(baseDN,
SearchScope.WHOLE_SUBTREE,
filter.toString(),
membershipUserAttribute);
while (entryReader.hasNext()) {
SearchResultEntry entry = entryReader.readEntry();
Attribute attr = entry.getAttribute(membershipUserAttribute);
if (attr != null) {
for (ByteString value : attr) {
membershipValue = value.toString();
}
}
}
}
filter = new AndFilter();
String userBaseDN = AttributeMapLoader.getBaseDN(principal,
getUserBaseDn(),
overrideCertDn);
filter.and(new EqualsFilter("objectClass", getObjectClass()))
.and(new EqualsFilter(getMemberNameAttribute(),
getMembershipUserAttribute() + "=" + membershipValue + ","
+ userBaseDN));
if (bindResult.isSuccess()) {
LOGGER.trace("Executing ldap search with base dn of {} and filter of {}",
groupBaseDn,
filter.toString());
entryReader = connection.search(groupBaseDn,
SearchScope.WHOLE_SUBTREE,
filter.toString(),
attributes);
SearchResultEntry entry;
while (entryReader.hasNext()) {
entry = entryReader.readEntry();
Attribute attr = entry.getAttribute(groupNameAttribute);
if (attr == null) {
LOGGER.trace("Claim '{}' is null", roleClaimType);
} else {
ProcessedClaim c = new ProcessedClaim();
c.setClaimType(getRoleURI());
c.setPrincipal(principal);
for (ByteString value : attr) {
String itemValue = value.toString();
c.addValue(itemValue);
}
claimsColl.add(c);
}
}
} else {
LOGGER.info("LDAP Connection failed.");
}
}
} catch (LdapException e) {
LOGGER.info(
"Cannot connect to server, therefore unable to set role claims. Set log level for \"ddf.security.sts.claimsHandler\" to DEBUG for more information.");
LOGGER.debug("Cannot connect to server, therefore unable to set role claims.", e);
} catch (SearchResultReferenceIOException e) {
LOGGER.info(
"Unable to set role claims. Set log level for \"ddf.security.sts.claimsHandler\" to DEBUG for more information.");
LOGGER.debug("Unable to set role claims.", e);
} finally {
if (connection != null) {
connection.close();
}
}
return claimsColl;
}
public void disconnect() {
connectionFactory.close();
}
public void setBindUserDN(String bindUserDN) {
this.bindUserDN = bindUserDN;
}
public void setBindUserCredentials(String bindUserCredentials) {
this.bindUserCredentials = bindUserCredentials;
}
public void setOverrideCertDn(boolean overrideCertDn) {
this.overrideCertDn = overrideCertDn;
}
}