/* * ==================== * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved. * * The contents of this file are subject to the terms of the Common Development * and Distribution License("CDDL") (the "License"). You may not use this file * except in compliance with the License. * * You can obtain a copy of the License at * http://IdentityConnectors.dev.java.net/legal/license.txt * See the License for the specific language governing permissions and limitations * under the License. * * When distributing the Covered Code, include this CDDL Header Notice in each file * and include the License file at identityconnectors/legal/license.txt. * If applicable, add the following below this CDDL Header, with the fields * enclosed by brackets [] replaced by your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * ==================== */ package org.identityconnectors.racf; import static org.identityconnectors.racf.RacfConstants.*; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.text.Normalizer; import java.text.Normalizer.Form; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import org.identityconnectors.common.CollectionUtil; import org.identityconnectors.framework.common.exceptions.ConnectorException; import org.identityconnectors.framework.common.exceptions.UnknownUidException; import org.identityconnectors.framework.common.objects.Attribute; import org.identityconnectors.framework.common.objects.AttributeBuilder; import org.identityconnectors.framework.common.objects.AttributeInfo; import org.identityconnectors.framework.common.objects.AttributeInfoBuilder; import org.identityconnectors.framework.common.objects.AttributeInfoUtil; import org.identityconnectors.framework.common.objects.AttributeUtil; import org.identityconnectors.framework.common.objects.ConnectorObject; import org.identityconnectors.framework.common.objects.ConnectorObjectBuilder; import org.identityconnectors.framework.common.objects.Name; import org.identityconnectors.framework.common.objects.ObjectClass; import org.identityconnectors.framework.common.objects.ObjectClassInfo; import org.identityconnectors.framework.common.objects.ObjectClassInfoBuilder; import org.identityconnectors.framework.common.objects.OperationOptions; import org.identityconnectors.framework.common.objects.OperationOptionsBuilder; import org.identityconnectors.framework.common.objects.OperationalAttributeInfos; import org.identityconnectors.framework.common.objects.OperationalAttributes; import org.identityconnectors.framework.common.objects.PredefinedAttributeInfos; import org.identityconnectors.framework.common.objects.PredefinedAttributes; import org.identityconnectors.framework.common.objects.ResultsHandler; import org.identityconnectors.framework.common.objects.Schema; import org.identityconnectors.framework.common.objects.SchemaBuilder; import org.identityconnectors.framework.common.objects.SyncResultsHandler; import org.identityconnectors.framework.common.objects.SyncToken; import org.identityconnectors.framework.common.objects.Uid; import org.identityconnectors.framework.common.objects.filter.EqualsFilter; import org.identityconnectors.framework.common.objects.filter.FilterTranslator; import org.identityconnectors.framework.spi.AttributeNormalizer; import org.identityconnectors.framework.spi.Configuration; import org.identityconnectors.framework.spi.Connector; import org.identityconnectors.framework.spi.ConnectorClass; import org.identityconnectors.framework.spi.operations.CreateOp; import org.identityconnectors.framework.spi.operations.DeleteOp; import org.identityconnectors.framework.spi.operations.ResolveUsernameOp; import org.identityconnectors.framework.spi.operations.SchemaOp; import org.identityconnectors.framework.spi.operations.SearchOp; import org.identityconnectors.framework.spi.operations.SyncOp; import org.identityconnectors.framework.spi.operations.TestOp; import org.identityconnectors.framework.spi.operations.UpdateOp; @ConnectorClass(configurationClass = RacfConfiguration.class, displayNameKey = "RACFConnector", messageCatalogPaths = {"org.identityconnectors.racf.Messages", "org.identityconnectors.rw3270.Messages", "org.identityconnectors.rw3270.hod.Messages", "org.identityconnectors.rw3270.wrq.Messages", "org.identityconnectors.rw3270.freehost3270.Messages"}) public class RacfConnector implements Connector, CreateOp, DeleteOp, SearchOp<String>, UpdateOp, SchemaOp, SyncOp, TestOp, ResolveUsernameOp { //DeleteOp, SearchOp<String>, UpdateOp, SchemaOp, SyncOp, TestOp, AttributeNormalizer, ResolveUsernameOp { static final List<String> POSSIBLE_ATTRIBUTES = Arrays.asList( "ADSP", "AUDITOR", "SPECIAL", "GRPACC", "OIDCARD", "OPERATIONS"); public static final String SEPARATOR = "*"; public static final String SEPARATOR_REGEX = "\\*"; public static final String RACF_GROUP_NAME = "RacfGroup"; public static final ObjectClass RACF_GROUP = new ObjectClass(RACF_GROUP_NAME); public static final String RACF_CONNECTION_NAME = "RacfConnection"; public static final ObjectClass RACF_CONNECTION = new ObjectClass(RACF_CONNECTION_NAME); private Map<String, AttributeInfo> _accountAttributes = null; private Map<String, AttributeInfo> _groupAttributes = null; private RacfConnection _connection; private RacfConfiguration _configuration; private CommandLineUtil _clUtil; private LdapUtil _ldapUtil; private SyncUtil _syncUtil; // Dateformats are not threadsafe, so not static // private final SimpleDateFormat _dateFormat = new SimpleDateFormat("MM/dd/yy"); private final SimpleDateFormat _resumeRevokeFormat = new SimpleDateFormat("MMMM dd, yyyy"); private static final Pattern _racfTimestamp = Pattern.compile("(\\d+)\\.(\\d+)(?:/(\\d+):(\\d+):(\\d+))?"); private static final Pattern _connectionPattern = Pattern.compile("racfuserid=([^+]+)\\+racfgroupid=([^,]+),.*", Pattern.CASE_INSENSITIVE); private final static Pattern _racfidPattern = Pattern.compile("racfid=([^,]*),.*", Pattern.CASE_INSENSITIVE); public RacfConnector() { } /** * {@inheritDoc} */ public void dispose() { if (_connection != null) { _connection.dispose(); } } /** * {@inheritDoc} */ public RacfConfiguration getConfiguration() { return this._configuration; } /** * {@inheritDoc} */ public void init(Configuration configuration) { try { _configuration = (RacfConfiguration) configuration; if (!_configuration.isNoCommandLine()) { _clUtil = new CommandLineUtil(this); } if (!_configuration.isNoLdap()) { _ldapUtil = new LdapUtil(this); } _connection = new RacfConnection(_configuration); _accountAttributes = null; _groupAttributes = null; // We want to init _accountAttributes and _groupAtributes here schema(); } catch (Exception e) { throw ConnectorException.wrap(e); } } public RacfConnection getConnection() { return _connection; } /** * {@inheritDoc} */ public Uid create(ObjectClass objectClass, Set<Attribute> attrs, OperationOptions options) { Set<Attribute> ldapAttrs = new HashSet<Attribute>(); Set<Attribute> commandLineAttrs = new HashSet<Attribute>(); Map<String, Attribute> attributes = AttributeUtil.toMap(attrs); splitUpOutgoingAttributes(objectClass, attributes, ldapAttrs, commandLineAttrs); if (isLdapConnectionAvailable()) { Uid uid = _ldapUtil.createViaLdap(objectClass, ldapAttrs, options); if (hasNonSpecialAttributes(commandLineAttrs)) { if (!isCommandLineAvailable()) { throw new ConnectorException(_configuration.getMessage(RacfMessages.NEED_COMMAND_LINE)); } _clUtil.updateViaCommandLine(objectClass, commandLineAttrs, options); } return uid; } else { if (hasNonSpecialAttributes(ldapAttrs)) { throw new ConnectorException(_configuration.getMessage(RacfMessages.NEED_LDAP)); } return _clUtil.createViaCommandLine(objectClass, commandLineAttrs, options); } } private boolean hasNonSpecialAttributes(Set<Attribute> attrs) { for (Attribute attribute : attrs) { if (!AttributeUtil.isSpecial(attribute)) { return true; } } return false; } private void splitUpOutgoingAttributes(ObjectClass objectClass, Map<String, Attribute> attributes, Set<Attribute> ldapAttrs, Set<Attribute> commandLineAttrs) { // Attribute consistency checking // Attribute enableDate = attributes.get(OperationalAttributes.ENABLE_DATE_NAME); Attribute disableDate = attributes.get(OperationalAttributes.DISABLE_DATE_NAME); Long now = new Date().getTime(); if (disableDate != null) { Long time = AttributeUtil.getLongValue(disableDate); if (time < now) { throw new IllegalArgumentException(_configuration.getMessage(RacfMessages.PAST_DISABLE_DATE)); } } if (enableDate != null) { Long time = AttributeUtil.getLongValue(enableDate); if (time < now) { throw new IllegalArgumentException(_configuration.getMessage(RacfMessages.PAST_ENABLE_DATE)); } } for (Attribute attribute : attributes.values()) { // Remap special attributes as needed // if (attribute.is(OperationalAttributes.PASSWORD_NAME)) { if (isLdapConnectionAvailable()) { attribute = AttributeBuilder.build(ATTR_LDAP_PASSWORD, attribute.getValue()); } else { attribute = AttributeBuilder.build(ATTR_CL_PASSWORD, attribute.getValue()); } } else if (attribute.is(OperationalAttributes.PASSWORD_EXPIRED_NAME)) { if (isLdapConnectionAvailable()) { attribute = AttributeBuilder.build(ATTR_LDAP_EXPIRED, attribute.getValue()); } else { attribute = AttributeBuilder.build(ATTR_CL_EXPIRED, attribute.getValue()); } } else if (attribute.is(OperationalAttributes.DISABLE_DATE_NAME)) { Date date = new Date(AttributeUtil.getLongValue(disableDate)); String dateValue = _dateFormat.format(date); attribute = AttributeBuilder.build(ATTR_CL_REVOKE_DATE, dateValue); } else if (attribute.is(OperationalAttributes.ENABLE_DATE_NAME)) { Date date = new Date(AttributeUtil.getLongValue(enableDate)); String dateValue = _dateFormat.format(date); attribute = AttributeBuilder.build(ATTR_CL_RESUME_DATE, dateValue); } else if (attribute.is(OperationalAttributes.ENABLE_NAME)) { attribute = AttributeBuilder.build(ATTR_CL_ENABLED, attribute.getValue()); } // Put the attribute on the appropriate attribute list(s) // if (attribute.is(Name.NAME) || attribute.is(Uid.NAME)) { commandLineAttrs.add(attribute); ldapAttrs.add(attribute); } else if (attribute.getName().contains(SEPARATOR) || ( !isLdapConnectionAvailable() && objectClass.is(RACF_CONNECTION_NAME) )) { // Even when we are in command-line form, use LDAP-style names for connection attributes, // since we don't get them via parsing // commandLineAttrs.add(convertToBasicASCII(attribute)); } else { ldapAttrs.add(convertToBasicASCII(attribute)); } } } private void splitUpIncomingAttributes(Set<String> attrs, Set<String> ldapAttrs, Set<String> commandLineAttrs) { for (String attribute : attrs) { // Remap special attributes as needed // if (attribute.equals(PredefinedAttributes.PASSWORD_CHANGE_INTERVAL_NAME)) { if (isLdapConnectionAvailable()) { ldapAttrs.add(ATTR_LDAP_PASSWORD_INTERVAL); } else { commandLineAttrs.add(ATTR_CL_PASSWORD_INTERVAL); } } else if (attribute.equals(PredefinedAttributes.LAST_LOGIN_DATE_NAME)) { if (isLdapConnectionAvailable()) { ldapAttrs.add(ATTR_LDAP_LAST_ACCESS); } else { commandLineAttrs.add(ATTR_CL_LAST_ACCESS); } } else if (attribute.equals(OperationalAttributes.ENABLE_NAME)) { if (isLdapConnectionAvailable()) { ldapAttrs.add(OperationalAttributes.ENABLE_NAME); } else { commandLineAttrs.add(ATTR_CL_ENABLED); } } else if (attribute.equals(PredefinedAttributes.LAST_PASSWORD_CHANGE_DATE_NAME)) { if (isLdapConnectionAvailable()) { ldapAttrs.add(ATTR_LDAP_PASSWORD_CHANGE); } else { commandLineAttrs.add(ATTR_CL_PASSDATE); } } else if (attribute.equals(OperationalAttributes.DISABLE_DATE_NAME)) { if (isLdapConnectionAvailable()) { ldapAttrs.add(ATTR_LDAP_REVOKE_DATE); } else { commandLineAttrs.add(ATTR_CL_REVOKE_DATE); } } else if (attribute.equals(OperationalAttributes.ENABLE_DATE_NAME)) { if (isLdapConnectionAvailable()) { ldapAttrs.add(ATTR_LDAP_RESUME_DATE); } else { commandLineAttrs.add(ATTR_CL_RESUME_DATE); } } else if (attribute.equals(OperationalAttributes.PASSWORD_NAME)) { if (isLdapConnectionAvailable()) { ldapAttrs.add("racfPasswordEnvelope"); } else { throw new IllegalArgumentException(_configuration.getMessage(RacfMessages.ATTRIBUTE_NOT_READABLE, OperationalAttributes.PASSWORD_NAME)); } } else if (attribute.equals(OperationalAttributes.PASSWORD_EXPIRED_NAME)) { if (isLdapConnectionAvailable()) { ldapAttrs.add(OperationalAttributes.PASSWORD_EXPIRED_NAME); } else { commandLineAttrs.add(ATTR_CL_EXPIRED); } } else if (attribute.equals(Name.NAME)) { commandLineAttrs.add(attribute); ldapAttrs.add(attribute); } else if (attribute.contains(SEPARATOR)) { commandLineAttrs.add(attribute); } else { ldapAttrs.add(attribute); } } } /** * {@inheritDoc} */ public void delete(ObjectClass objectClass, Uid uid, OperationOptions options) { if (isLdapConnectionAvailable()) { _ldapUtil.deleteViaLdap(objectClass, uid); } else { _clUtil.deleteViaCommandLine(objectClass, uid); } } /** * {@inheritDoc} */ public FilterTranslator<String> createFilterTranslator(ObjectClass oclass, OperationOptions options) { if (isLdapConnectionAvailable()) { if (oclass.is(ObjectClass.ACCOUNT_NAME)) { return new RacfUserFilterTranslator(); } if (oclass.is(RACF_GROUP_NAME)) { return new RacfGroupFilterTranslator(); } if (oclass.is(RACF_CONNECTION_NAME)) { return new RacfConnectFilterTranslator(); } else { throw new ConnectorException(_configuration.getMessage(RacfMessages.UNSUPPORTED_OBJECT_CLASS, oclass)); } } else { if (oclass.is(ObjectClass.ACCOUNT_NAME)) { return new RacfCommandLineFilterTranslator(_configuration); } if (oclass.is(RACF_GROUP_NAME)) { return new RacfCommandLineFilterTranslator(_configuration); } else { throw new ConnectorException(_configuration.getMessage(RacfMessages.UNSUPPORTED_OBJECT_CLASS, oclass)); } } } /** * {@inheritDoc} */ public void executeQuery(ObjectClass objectClass, String query, ResultsHandler handler, OperationOptions options) { System.out.println("executeQuery:" + query); List<String> names = null; if (objectClass.is(ObjectClass.ACCOUNT_NAME)) { names = getUsers(query); // Need to exit if null... } else if (objectClass.is(RACF_GROUP_NAME)) { names = getGroups(query); // Need to exit if null... } else { throw new ConnectorException(_configuration.getMessage(RacfMessages.UNSUPPORTED_OBJECT_CLASS, objectClass)); } try { TreeSet<String> attributesToGet = new TreeSet<String>(); //schema(); if (options != null && options.getAttributesToGet() != null) { attributesToGet = new TreeSet<String>(); for (String name : options.getAttributesToGet()) { //TODO: Gael - Selected objectclass should be validated here... otherwise we pick every attributes from connector config attributesToGet.add(name); } } else { if (objectClass.is(ObjectClass.ACCOUNT_NAME)) { attributesToGet = getDefaultAttributes(_accountAttributes); } else if (objectClass.is(RACF_GROUP_NAME)) { attributesToGet = getDefaultAttributes(_groupAttributes); } } boolean wantUid = ( attributesToGet != null && attributesToGet.remove(Uid.NAME) ); boolean getNameOnly = ( attributesToGet != null && attributesToGet.size() == 1 && Name.NAME.equalsIgnoreCase(attributesToGet.first()) ); boolean getNothing = ( attributesToGet != null && attributesToGet.size() == 0 ); // It's an error to request attributes from a source we can't use // Set<String> ldapAttrs = new TreeSet<String>(); Set<String> commandLineAttrs = new TreeSet<String>(); splitUpIncomingAttributes(attributesToGet, ldapAttrs, commandLineAttrs); int ldapSize = ldapAttrs.size(); if (ldapAttrs.contains(Name.NAME)) { ldapSize--; } if (!isLdapConnectionAvailable() && ldapSize > 0) { throw new IllegalArgumentException(_configuration.getMessage(RacfMessages.ATTRS_NO_LDAP, ldapAttrs.toString())); } int commandLineSize = commandLineAttrs.size(); if (commandLineAttrs.contains(Name.NAME)) { commandLineSize--; } if (!isCommandLineAvailable() && commandLineSize > 0) { throw new IllegalArgumentException(_configuration.getMessage(RacfMessages.ATTRS_NO_CL)); } for (String name : names) { try { // We can special case getting at most just name // ConnectorObject object = null; if (getNameOnly || getNothing) { ConnectorObjectBuilder builder = new ConnectorObjectBuilder(); builder.setObjectClass(objectClass); builder.setUid(name); builder.setName(name); object = builder.build(); } else { Map<String, Object> ldapValues = new HashMap<String, Object>(); if (ldapSize > 0) { ldapValues = _ldapUtil.getAttributesFromLdap(objectClass, name, ldapAttrs); } Map<String, Object> clValues = new HashMap<String, Object>(); if (commandLineSize > 0) { clValues = _clUtil.getAttributesFromCommandLine(objectClass, name, commandLineAttrs); } object = buildObject(objectClass, ldapValues, clValues, attributesToGet, wantUid); } handler.handle(object); } catch (UnknownUidException uue) { // Ignore this, user disappeared during query } } } catch (NamingException e) { throw new ConnectorException(e); } } private boolean isCommandLineAvailable() { return !_configuration.isNoCommandLine() && !ConnectionPool.getConnectionPool(_configuration).isEmpty(); } private TreeSet<String> getDefaultAttributes(Map<String, AttributeInfo> infos) { TreeSet<String> results = new TreeSet<String>(); for (Map.Entry<String, AttributeInfo> entry : infos.entrySet()) { if (entry.getValue().isReturnedByDefault()) { results.add(entry.getKey()); } } return results; } private boolean isEmpty(Map<?, ?> map) { return ( map == null || map.isEmpty() ); } private ConnectorObject buildObject(ObjectClass objectClass, Map<String, Object> attributesFromLdap, Map<String, Object> attributesFromCommandLine, Set<String> attributesToGetOrig, boolean wantUid) throws NamingException { ConnectorObjectBuilder builder = new ConnectorObjectBuilder(); Set<String> attributesToGet = CollectionUtil.newCaseInsensitiveSet(); attributesToGet.addAll(attributesToGetOrig); Uid uid = null; if (!isEmpty(attributesFromLdap)) { uid = (Uid) attributesFromLdap.remove(Uid.NAME); builder.setUid(uid); String name = (String) attributesFromLdap.remove(Name.NAME); //name = LdapUtil.createUniformUid(name, _configuration.getSuffix()); builder.setName(name); addAttributes(objectClass, attributesFromLdap, attributesToGet, builder); } if (!isEmpty(attributesFromCommandLine)) { if (isEmpty(attributesFromLdap)) { String name = ( (String) attributesFromCommandLine.get(ATTR_CL_USERID) ).toUpperCase(); name = LdapUtil.createUniformUid(name, _configuration.getSuffix()); uid = new Uid(name); builder.setUid(uid); builder.setName(name); } addAttributes(objectClass, attributesFromCommandLine, attributesToGet, builder); } if (wantUid) { builder.addAttribute(uid); } builder.setObjectClass(objectClass); ConnectorObject next = builder.build(); return next; } private void addAttributes(ObjectClass objectClass, Map<String, Object> attributesFromCommandLine, Set<String> attributesToGet, ConnectorObjectBuilder builder) { for (Map.Entry<String, Object> entry : attributesFromCommandLine.entrySet()) { String name = entry.getKey(); Object value = entry.getValue(); if (includeInAttributes(objectClass, name, attributesToGet)) { if (value instanceof Collection<?>) { builder.addAttribute(name, (Collection<?>) value); } else if (value == null) { builder.addAttribute(name); } else { builder.addAttribute(name, value); } } } } List<String> getMembersOfGroup(String group) { if (isLdapConnectionAvailable()) { return _ldapUtil.getMembersOfGroupViaLdap(group); } else { return _clUtil.getMembersOfGroupViaCommandLine(group); } } void setGroupMembershipsForUser(String name, Attribute groupsAttribute, Attribute ownersAttribute) { setGroupMembershipsForUser(name, groupsAttribute, ownersAttribute, null, null); } void setGroupMembershipsForUser(String name, Attribute groupsAttribute, Attribute ownersAttribute, String defaultGroup) { setGroupMembershipsForUser(name, groupsAttribute, ownersAttribute, null, defaultGroup); } void setGroupMembershipsForUser(String name, Attribute groupsAttribute, Attribute ownersAttribute, javax.naming.directory.Attribute curGroupsAttribute, String defaultGroup) { checkConnectionConsistency(groupsAttribute, ownersAttribute); List<Object> groups = groupsAttribute.getValue(); List<Object> owners = ownersAttribute == null ? null : ownersAttribute.getValue(); List<String> currentGroups; if (curGroupsAttribute == null) { currentGroups = getGroupsForUser(name); } else { currentGroups = new ArrayList(); try { NamingEnumeration curValue = curGroupsAttribute.getAll(); while (curValue.hasMoreElements()) { currentGroups.add(extractRacfIdFromLdapId((String) curValue.next())); } } catch (Exception e) { } } if (defaultGroup == null) { defaultGroup = currentGroups.get(0); // TODO: Gael - This is a wrong assumption.... on LDAP at least } defaultGroup = extractRacfIdFromLdapId(defaultGroup); for (String currentGroup : currentGroups) { if (!groups.contains(currentGroup) && !currentGroup.equalsIgnoreCase(defaultGroup)) { //TODO improve this... lower/upper case issue // Group is being eliminated // // TODO: CHECK THIS String connectionName = createConnectionId(name, currentGroup); delete(RACF_CONNECTION, new Uid(connectionName), null); } } for (int i = 0; i < groups.size(); i++) { Object newGroup = groups.get(i); Object newOwner = ownersAttribute == null ? null : owners.get(i); if (!currentGroups.contains(newGroup)) { // Group is being added // // TODO: CHECK THIS String connectionName = createConnectionId(name, (String) newGroup); Set<Attribute> attributes = new HashSet<Attribute>(); attributes.add(AttributeBuilder.build(Name.NAME, connectionName)); if (newOwner != null) { attributes.add(AttributeBuilder.build(ATTR_LDAP_CONNECT_OWNER, newOwner)); } attributes.add(AttributeBuilder.build("objectclass", "racfConnect")); create(RACF_CONNECTION, attributes, new OperationOptions(new HashMap<String, Object>())); } } } void checkConnectionConsistency(Attribute groupsAttribute, Attribute ownersAttribute) { // members and owners must be the same length // boolean badSize = false; try { if (ownersAttribute != null) { badSize = ( groupsAttribute.getValue().size() != ownersAttribute.getValue().size() ); } } catch (NullPointerException npe) { badSize = true; } if (badSize) { throw new IllegalArgumentException(_configuration.getMessage(RacfMessages.OWNER_INCONSISTENT)); } } private String createConnectionId(String name, String currentGroup) { //name = extractRacfIdFromLdapId(name); // TODO: How can this work? current group is probably a DN currentGroup = extractRacfIdFromLdapId(currentGroup); String connectionName = "racfuserid=" + name + "+racfgroupid=" + currentGroup + ",profileType=connect," + _configuration.getSuffix(); return connectionName; } void setGroupMembershipsForGroups(String name, Attribute membersAttribute, Attribute ownersAttribute) { checkConnectionConsistency(membersAttribute, ownersAttribute); List<Object> members = membersAttribute.getValue(); List<Object> owners = ownersAttribute == null ? null : ownersAttribute.getValue(); List<String> currentMembers = getMembersOfGroup(name); for (String currentMember : currentMembers) { if (!members.contains(currentMember)) { String connectionName = createConnectionId(currentMember, name); delete(RACF_CONNECTION, new Uid(connectionName), null); } } for (int i = 0; i < members.size(); i++) { Object newMember = members.get(i); Object newOwner = ownersAttribute == null ? null : owners.get(i); if (!currentMembers.contains(newMember)) { // Member is being added // String connectionName = createConnectionId((String) newMember, name); Set<Attribute> attributes = new HashSet<Attribute>(); attributes.add(AttributeBuilder.build(Name.NAME, connectionName)); if (newOwner != null) { attributes.add(AttributeBuilder.build(ATTR_LDAP_CONNECT_OWNER, newOwner)); } attributes.add(AttributeBuilder.build("objectclass", "racfConnect")); create(RACF_CONNECTION, attributes, new OperationOptions(new HashMap<String, Object>())); } } } List<String> getGroupsForUser(String user) { if (isLdapConnectionAvailable()) { return _ldapUtil.getGroupsForUserViaLdap(user); } else { return _clUtil.getGroupsForUserViaCommandLine(user); } } /** * Extract the RACF account id from a RACF LDAP Uid. * * @param uid * @return */ String createAccountNameFromUid(Uid uid) { String uidString = uid.getUidValue(); return extractRacfIdFromLdapId(uidString); } /** * Create a RACF LDAP Uid given a name. * * @param name * @return */ Uid createUidFromName(ObjectClass objectClass, String name) { if (objectClass.is(ObjectClass.ACCOUNT_NAME)) { return new Uid("racfid=" + name.toUpperCase() + ",profiletype=user," + _configuration.getSuffix()); } else if (objectClass.is(RACF_GROUP_NAME)) { return new Uid("racfid=" + name.toUpperCase() + ",profiletype=group," + _configuration.getSuffix()); } else { return null; } } static String extractRacfIdFromLdapId(String uidString) { Matcher matcher = _racfidPattern.matcher(uidString); if (matcher.matches()) { return matcher.group(1); } else { return uidString; } } static String[] extractRacfIdAndGroupIdFromLdapId(String uidString) { Matcher matcher = _connectionPattern.matcher(uidString); if (matcher.matches()) { return new String[]{matcher.group(1), matcher.group(2)}; } else { return null; } } /** * Get the names of the users satisfying the query. * * @param query -- a query to select users * @return a List<String> of user names */ private List<String> getUsers(String query) { // TODO: Do we want to allow having LDAP do the query via command line // if the query is "*" or null if (isLdapConnectionAvailable()) { return _ldapUtil.getUsersViaLdap(query); } else { return _clUtil.getUsersViaCommandLine(query); } } /** * Get the names of the groups satisfying the query. * * @param query -- a query to select groups * @return a List<String> of group names */ private List<String> getGroups(String query) { if (isLdapConnectionAvailable()) { return _ldapUtil.getGroupsViaLdap(query); } else { return _clUtil.getGroupsViaCommandLine(query); } } public Uid update(ObjectClass obj, Uid uid, Set<Attribute> attrs, OperationOptions options) { return update(obj, AttributeUtil.addUid(attrs, uid), options); } /** * {@inheritDoc} */ Uid update(ObjectClass objectClass, Set<Attribute> attrs, OperationOptions options) { Set<Attribute> ldapAttrs = new HashSet<Attribute>(); Set<Attribute> commandLineAttrs = new HashSet<Attribute>(); if (AttributeUtil.getNameFromAttributes(attrs) != null) { throw new IllegalArgumentException(_configuration.getMessage(RacfMessages.ATTRIBUTE_NOT_UPDATEABLE, Name.NAME)); } Map<String, Attribute> attributes = CollectionUtil.<Attribute>newCaseInsensitiveMap(); for (Attribute attr : attrs) { attributes.put(attr.getName(), attr); } // If PASSWORD is specified, but EXPIRED is not, // we must reconstruct the value for EXPIRED by reading the user. // if (!attributes.containsKey(OperationalAttributes.PASSWORD_EXPIRED_NAME) && attributes.containsKey(OperationalAttributes.PASSWORD_NAME)) { Uid uid = AttributeUtil.getUidAttribute(attrs); List<String> query = createFilterTranslator(objectClass, options).translate(new EqualsFilter(uid)); LocalHandler handler = new LocalHandler(); OperationOptionsBuilder localOptionsBuilder = new OperationOptionsBuilder(); localOptionsBuilder.setAttributesToGet(ATTR_LDAP_PASSWORD_CHANGE); executeQuery(objectClass, query.get(0), handler, localOptionsBuilder.build()); Iterator<ConnectorObject> iterator = handler.iterator(); if (iterator.hasNext()) { ConnectorObject object = iterator.next(); Attribute expired = object.getAttributeByName(OperationalAttributes.PASSWORD_EXPIRED_NAME); if (expired != null) { attributes.put(OperationalAttributes.PASSWORD_EXPIRED_NAME, expired); } } } splitUpOutgoingAttributes(objectClass, attributes, ldapAttrs, commandLineAttrs); if (isLdapConnectionAvailable()) { Uid uid = _ldapUtil.updateViaLdap(objectClass, ldapAttrs, options); if (hasNonSpecialAttributes(commandLineAttrs)) { if (!isCommandLineAvailable()) { throw new ConnectorException(_configuration.getMessage(RacfMessages.NEED_COMMAND_LINE)); } _clUtil.updateViaCommandLine(objectClass, commandLineAttrs, options); } return uid; } else { if (hasNonSpecialAttributes(ldapAttrs)) { throw new ConnectorException(_configuration.getMessage(RacfMessages.NEED_LDAP)); } return _clUtil.updateViaCommandLine(objectClass, commandLineAttrs, options); } } private Schema clSchema() { final SchemaBuilder schemaBuilder = new SchemaBuilder(getClass()); // RACF Users // { Set<AttributeInfo> attributes = new HashSet<AttributeInfo>(); // Required Attributes // attributes.add(buildNonupdateAttribute(Name.NAME, String.class, true)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_DFLTGRP, String.class)); attributes.add(buildMultivaluedAttribute(ATTR_CL_GROUP_CONN_OWNERS, String.class, false)); attributes.add(buildMultivaluedAttribute(ATTR_CL_GROUPS, String.class, false)); // Optional Attributes (have RACF default values) // attributes.add(AttributeInfoBuilder.build(ATTR_CL_OWNER, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_NAME, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_DATA, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_TSO_ACCTNUM, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_TSO_HOLDCLASS, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_TSO_JOBCLASS, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_TSO_MSGCLASS, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_TSO_PROC, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_TSO_SIZE, Integer.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_TSO_MAXSIZE, Integer.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_TSO_SYSOUTCLASS, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_TSO_UNIT, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_TSO_USERDATA, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_TSO_COMMAND, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_OMVS_UID, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_OMVS_HOME, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_OMVS_PROGRAM, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_OMVS_CPUTIMEMAX, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_OMVS_ASSIZEMAX, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_OMVS_FILEPROCMAX, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_OMVS_PROCUSERMAX, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_OMVS_THREADSMAX, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_OMVS_MMAPAREAMAX, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_CICS_TIMEOUT, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_CICS_OPPRTY, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_CICS_OPIDENT, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_CICS_XRFSOFF, String.class)); attributes.add(buildMultivaluedAttribute(ATTR_CL_CICS_OPCLASS, Integer.class, false)); attributes.add(buildMultivaluedAttribute(ATTR_CL_CICS_RSLKEY, Integer.class, false)); attributes.add(buildMultivaluedAttribute(ATTR_CL_CICS_TSLKEY, Integer.class, false)); attributes.add(buildMultivaluedAttribute(ATTR_CL_NETVIEW_OPCLASS, String.class, false)); attributes.add(buildMultivaluedAttribute(ATTR_CL_NETVIEW_DOMAINS, String.class, false)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_NETVIEW_NGMFVSPN, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_NETVIEW_NGMFADMN, boolean.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_NETVIEW_MSGRECVR, boolean.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_NETVIEW_IC, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_NETVIEW_CTL, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_CL_NETVIEW_CONSNAME, String.class)); // Multi-valued attributes // attributes.add(buildMultivaluedAttribute(ATTR_CL_ATTRIBUTES, String.class, false)); // Catalog Attributes (make non-default) // attributes.add(buildNonDefaultAttribute(ATTR_CL_MASTER_CATALOG, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_CL_USER_CATALOG, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_CL_CATALOG_ALIAS, String.class)); // Update-only attributes // attributes.add(buildUpdateonlyAttribute(ATTR_CL_TSO_DELETE_SEGMENT, String.class, false)); // Operational Attributes // attributes.add(buildReadonlyAttribute(PredefinedAttributes.PASSWORD_CHANGE_INTERVAL_NAME, long.class)); attributes.add(OperationalAttributeInfos.ENABLE); attributes.add(OperationalAttributeInfos.ENABLE_DATE); attributes.add(OperationalAttributeInfos.DISABLE_DATE); attributes.add(OperationalAttributeInfos.PASSWORD); attributes.add(OperationalAttributeInfos.PASSWORD_EXPIRED); attributes.add(PredefinedAttributeInfos.LAST_LOGIN_DATE); attributes.add(PredefinedAttributeInfos.LAST_PASSWORD_CHANGE_DATE); _accountAttributes = AttributeInfoUtil.toMap(attributes); ObjectClassInfoBuilder bld = new ObjectClassInfoBuilder(); bld.setType(ObjectClass.ACCOUNT_NAME); bld.addAllAttributeInfo(attributes); ObjectClassInfo objectClassInfo = bld.build(); schemaBuilder.defineObjectClass(objectClassInfo); // Sync is not supported for Command-Line connector // schemaBuilder.removeSupportedObjectClass(SyncOp.class, objectClassInfo); } //---------------------------------------------------------------------- // RACF Groups // { Set<AttributeInfo> groupAttributes = new HashSet<AttributeInfo>(); groupAttributes.add(buildNonupdateAttribute(Name.NAME, String.class, true)); groupAttributes.add(AttributeInfoBuilder.build(ATTR_CL_SUPGROUP, String.class)); groupAttributes.add(AttributeInfoBuilder.build(ATTR_CL_OWNER, String.class)); groupAttributes.add(AttributeInfoBuilder.build(ATTR_CL_DATA, String.class)); groupAttributes.add(buildMultivaluedAttribute(ATTR_CL_MEMBERS, String.class, false)); groupAttributes.add(buildMVROAttribute(ATTR_CL_GROUPS, String.class)); _groupAttributes = AttributeInfoUtil.toMap(groupAttributes); ObjectClassInfoBuilder bld = new ObjectClassInfoBuilder(); bld.setType(RACF_GROUP_NAME); bld.addAllAttributeInfo(groupAttributes); ObjectClassInfo objectClassInfo = bld.build(); schemaBuilder.defineObjectClass(objectClassInfo); // Sync is not supported for Command-Line connector // schemaBuilder.removeSupportedObjectClass(SyncOp.class, objectClassInfo); } return schemaBuilder.build(); } private Schema ldapSchema() { final SchemaBuilder schemaBuilder = new SchemaBuilder(getClass()); Set<String> userObjectClasses; Set<String> groupObjectClasses; userObjectClasses = CollectionUtil.newCaseInsensitiveSet(); if (_configuration.getUserObjectClasses() != null) { for (String userObjectClass : _configuration.getUserObjectClasses()) { userObjectClasses.add(userObjectClass); } } groupObjectClasses = CollectionUtil.newCaseInsensitiveSet(); if (_configuration.getGroupObjectClasses() != null) { for (String groupObjectClass : _configuration.getGroupObjectClasses()) { groupObjectClasses.add(groupObjectClass); } } // RACF SCHEMA // As documented here: // http://publib.boulder.ibm.com/infocenter/zvm/v5r4/index.jsp?topic=/com.ibm.zvm.v54.kldl0/tivp04.htm // RACF Users // { Set<AttributeInfo> attributes = new HashSet<AttributeInfo>(); // Required Attributes // attributes.add(buildReadonlyAttribute(ATTR_LDAP_ACCOUNTID, String.class)); attributes.add(buildNonupdateAttribute(Name.NAME, String.class, true)); attributes.add(AttributeInfoBuilder.build(ATTR_LDAP_DEFAULT_GROUP, String.class)); // Optional Attributes (have RACF default values) // // racfBaseCommon // common base class for all RACF profiles // (SUP top ) // MAY ( racfOwner $ racfInstallationData $ racfDatasetModel $ racfAuthorizationDate ) attributes.add(AttributeInfoBuilder.build(ATTR_LDAP_DATA, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_LDAP_MODEL, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_LDAP_OWNER, String.class)); // racfUser // RACFUSER Profile entry // SUP ( racfBaseCommon ) // MUST ( racfid ) attributes.add(buildReadonlyAttribute(ATTR_LDAP_ID, String.class)); //MAY ( racfAuthorizationDate $ racfAttributes $ racfPassword $ racfPasswordChangeDate $ // racfPasswordEnvelope $ racfPasswordInterval $ racfProgrammerName $ racfDefaultGroup $ // racfLastAccess $ racfSecurityLabel $ racfSecurityCategoryList $ racfRevokeDate $ // racfResumeDate $ racfLogonDays $ racfLogonTime $ racfClassName $ racfConnectGroupName $ // racfConnectGroupAuthority $ racfConnectGroupUACC $ racfSecurityLevel $ racfPassPhrase $ // racfPassPhraseChangeDate $ racfHavePasswordEnvelope $ racfPassPhraseEnvelope $ racfHavePassPhraseEnvelope ) attributes.add(buildReadonlyAttribute(ATTR_LDAP_AUTHORIZATION_DATE, String.class)); attributes.add(buildMultivaluedAttribute(ATTR_LDAP_ATTRIBUTES, String.class, false)); attributes.add(buildReadonlyAttribute(ATTR_LDAP_PASSWORD_CHANGE, String.class)); // password envelope? attributes.add(buildReadonlyAttribute(ATTR_LDAP_PASSWORD_INTERVAL, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_LDAP_PROGRAMMER_NAME, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_LDAP_DEFAULT_GROUP, String.class)); attributes.add(buildReadonlyAttribute(ATTR_LDAP_LAST_ACCESS, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_LDAP_SECURITY_LABEL, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_LDAP_SECURITY_LEVEL, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_LDAP_SECURITY_CAT_LIST, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_LDAP_LOGON_DAYS, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_LDAP_LOGON_TIME, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_LDAP_CLASS_NAME, String.class)); // SAFDfpSegment // SAF DFP portions of a RACF USER or GROUP profile // SUP ( top ) // MAY ( SAFDfpDataApplication $ SAFDfpDataClass $ SAFDfpManagementClass $ SAFDfpStorageClass ) ) if (userObjectClasses.contains("SAFDfpSegment")) { attributes.add(buildNonDefaultAttribute(ATTR_LDAP_DPF_DATA_APP, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_DPF_DATA_CLASS, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_DPF_MGMT_CLASS, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_DPF_STORAGE_CLASS, String.class)); } // SAFTsoSegment // OS/390 TSO information in a RACF USER profile // SUP ( top ) // MAY ( SAFAccountNumber $ SAFDestination $ SAFHoldClass $ SAFJobClass $ SAFMessageClass $ // SAFDefaultLoginProc $ SAFLogonSize $ SAFMaximumRegionSize $ SAFDefaultSysoutClass $ SAFUserdata $ // SAFDefaultUnit $ SAFTsoSecurityLabel $ SAFDefaultCommand ) if (userObjectClasses.contains("SAFTsoSegment")) { attributes.add(buildNonDefaultAttribute(ATTR_LDAP_TSO_ACCOUNT_NUMBER, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_TSO_DEFAULT_CMD, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_TSO_DESTINATION, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_TSO_MESSAGE_CLASS, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_TSO_DEFAULT_LOGIN, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_TSO_LOGON_SIZE, Integer.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_TSO_MAX_REGION_SIZE, Integer.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_TSO_DEFAULT_SYSOUT, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_TSO_USERDATA, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_TSO_DEFAULT_UNIT, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_TSO_SECURITY_LABEL, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_TSO_HOLD_CLASS, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_TSO_JOB_CLASS, String.class)); } // racfLanguageSegment // OS/390 language information in a RACF USER profile // SUP ( top ) // MAY ( racfPrimaryLanguage $ racfSecondaryLanguage ) if (userObjectClasses.contains("racfLanguageSegment")) { attributes.add(buildNonDefaultAttribute(ATTR_LDAP_LANG_PRIMARY, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_LANG_SECONDARY, String.class)); } // racfCicsSegment // OS/390 CICS information in a RACF USER profile // SUP ( top ) // MAY ( racfOperatorClass $ racfOperatorIdentification $ racfOperatorPriority $ racfOperatorReSignon $ // racfRslKey $ racfTerminalTimeout $ racfTslKey ) if (userObjectClasses.contains("racfCicsSegment")) { attributes.add(buildNonDefaultAttribute(ATTR_LDAP_CICS_OPER_ID, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_CICS_OPER_CLASS, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_CICS_OPER_PRIORITY, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_CICS_OPER_RESIGNON, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_CICS_TERM_TIMEOUT, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_CICS_TSLKEY, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_CICS_RSLKEY, String.class)); } // racfOperparmSegment // OS/390 Operator parameters in a RACF USER profile // SUP ( top ) // MAY ( racfStorageKeyword $ racfAuthKeyword $ racfMformKeyword $ racfLevelKeyword $ racfMonitorKeyword $ // racfRoutcodeKeyword $ racfLogCommandResponseKeyword $ racfMGIDKeyword $ racfDOMKeyword $ // racfKEYKeyword $ racfCMDSYSKeyword $ racfUDKeyword $ racfMscopeSystems $ racfAltGroupKeyword $ // racfAutoKeyword $ racfHcKeyword $ racfIntidsKeyword $ racfUnknidsKeyword ) if (userObjectClasses.contains("racfOperparmSegment")) { attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OP_STORAGE, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OP_AUTH, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OP_MFORM, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OP_LEVEL, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OP_MONITOR, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OP_ROUTCODE, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OP_LOG_CMD_RESPONSE, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OP_MGID, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OP_DOM, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OP_KEY, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OP_CMDSYS, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OP_UD, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OP_MSCOPE_SYSTEMS, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OP_ALTGROUP, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OP_AUTO, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OP_HC, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OP_INTIDS, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OP_UNKNIDS, String.class)); } // racfWorkAttrSegment // OS/390 work attributes information in a RACF USER profile' AUXILIARY SUP ( top ) // MAY ( racfWorkAttrUsername $ racfBuilding $ racfDepartment $ racfRoom $ racfAddressLine1 $ // racfAddressLine2 $ racfAddressLine3 $ racfAddressLine4 $ racfWorkAttrAccountNumber ) if (userObjectClasses.contains("racfWorkAttrSegment")) { attributes.add(buildNonDefaultAttribute(ATTR_LDAP_WA_USER_NAME, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_WA_BUILDING, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_WA_DEPARTMENT, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_WA_ROOM, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_WA_ADDRESS_LINE1, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_WA_ADDRESS_LINE2, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_WA_ADDRESS_LINE3, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_WA_ADDRESS_LINE4, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_WA_ACCOUNT_NUMBER, String.class)); } // racfUserOmvsSegment // OS/390 OMVS User information portion of a RACF USER profile // SUP ( top ) // MAY ( racfOmvsUid $ racfOmvsHome $ racfOmvsInitialProgram $ racfOmvsMaximumAddressSpaceSize $ // racfOmvsMaximumCPUTime $ racfOmvsMaximumFilesPerProcess $ racfOmvsMaximumMemoryMapArea $ // racfOmvsMaximumProcessesPerUID $ racfOmvsMaximumThreadsPerProcess $ racfOmvsMemoryLimit $ // racfOmvsSharedMemoryMaximum $ racfOmvsUidKeyword ) if (userObjectClasses.contains("racfUserOmvsSegment")) { attributes.add(AttributeInfoBuilder.build(ATTR_LDAP_OMVS_UID, String.class)); attributes.add(AttributeInfoBuilder.build(ATTR_LDAP_OMVS_HOME, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OMVS_INIT_PROGRAM, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OMVS_MAX_CPUTIME, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OMVS_MAX_PROCESSES, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OMVS_MAX_ADDR_SPACE, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OMVS_MAX_FILES, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OMVS_MAX_THREADS, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OMVS_MAX_MEMORY_MAP, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OMVS_MAX_MEMORY_LIMIT, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OMVS_SHARED_MEM_MAX, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OMVS_UID_KEYWORD, String.class)); } // racfNetviewSegment // OS/390 Netview information in a RACF USER profile // SUP ( top ) // MAY ( racfNetviewInitialCommand $ racfDefaultConsoleName $ racfCTLKeyword $ racfMSGRCVRKeyword $ // racfNetviewOperatorClass $ racfDomains $ racfNGMFADMKeyword $ racfNGMFVSPNKeyword ) if (userObjectClasses.contains("racfNetviewSegment")) { attributes.add(buildNonDefaultAttribute(ATTR_LDAP_NV_INITIALCMD, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_NV_DEFAULT_CONSOLE, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_NV_CTL, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_NV_MESSAGE_RECEIVER, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_NV_OPERATOR_CLASS, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_NV_DOMAINS, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_NV_NGMFADM, String.class)); } // racfDCESegment // OS/390 DCE information in a RACF USER profile' // SUP ( top ) // MAY ( racfDCEAutoLogin $ racfDCEHomeCell $ racfDCEHomeCellUUID $ racfDCEPrincipal $ racfDCEUUID ) if (userObjectClasses.contains("racfDCESegment")) { attributes.add(buildNonDefaultAttribute(ATTR_LDAP_NV_DCE_UUID, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_NV_DCE_PRINCIPAL, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_NV_DCE_HOME_CELL, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_NV_DCE_HOME_CELL_UUID, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_NV_DCE_AUTOLOGIN, String.class)); } // racfUserOvmSegment // OS/390 OVM User information portion of a RACF USER profile // SUP ( top ) // MAY ( racfOvmUid $ racfOvmHome $ racfOvmInitialProgram $ racfOvmFileSystemRoot ) if (userObjectClasses.contains("racfUserOvmSegment")) { attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OVM_UID, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OVM_HOME, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OVM_INITIAL_PROGRAM, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_OVM_FILESYSTEM_ROOT, String.class)); } // racfLNotesSegment // OS/390 LNOTES segment information in a RACF USER profile // SUP ( top ) // MAY ( racfLNotesShortName ) if (userObjectClasses.contains("racfLNotesSegment")) { attributes.add(buildNonDefaultAttribute(ATTR_LDAP_LN_SHORT_NAME, String.class)); } // racfNDSSegment // OS/390 NDS segment information in a RACF USER profile // SUP ( top ) // MAY ( racfNDSUserName ) ) if (userObjectClasses.contains("racfNDSSegment")) { attributes.add(buildNonDefaultAttribute(ATTR_LDAP_NDS_USER_NAME, String.class)); } if (userObjectClasses.contains("racfKerberosInfo")) { attributes.add(buildNonDefaultAttribute(ATTR_LDAP_KERB_NAME, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_KERB_MAX_TICKET_LIFE, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_KERB_ENCRYPT, String.class)); } if (userObjectClasses.contains("racfProxySegment")) { attributes.add(buildNonDefaultAttribute(ATTR_LDAP_PROXY_BINDDN, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_PROXY_BINDPW, String.class)); attributes.add(buildNonDefaultAttribute(ATTR_LDAP_PROXY_HOST, String.class)); } // Multi-valued attributes // attributes.add(buildReadOnlyMultivaluedAttribute(ATTR_LDAP_GROUPS, String.class)); attributes.add(buildReadOnlyMultivaluedAttribute(ATTR_LDAP_CONNECT_OWNER, String.class)); // Operational Attributes // attributes.add(buildReadonlyAttribute(PredefinedAttributes.PASSWORD_CHANGE_INTERVAL_NAME, long.class)); if (isCommandLineAvailable()) { attributes.add(OperationalAttributeInfos.ENABLE); attributes.add(OperationalAttributeInfos.ENABLE_DATE); attributes.add(OperationalAttributeInfos.DISABLE_DATE); } else { attributes.add(buildReadonlyAttribute(OperationalAttributes.ENABLE_NAME, OperationalAttributeInfos.ENABLE.getType())); attributes.add(buildReadonlyAttribute(OperationalAttributes.ENABLE_DATE_NAME, OperationalAttributeInfos.ENABLE_DATE.getType())); attributes.add(buildReadonlyAttribute(OperationalAttributes.DISABLE_DATE_NAME, OperationalAttributeInfos.DISABLE_DATE.getType())); } attributes.add(OperationalAttributeInfos.PASSWORD); attributes.add(OperationalAttributeInfos.PASSWORD_EXPIRED); attributes.add(PredefinedAttributeInfos.LAST_LOGIN_DATE); attributes.add(PredefinedAttributeInfos.LAST_PASSWORD_CHANGE_DATE); _accountAttributes = AttributeInfoUtil.toMap(attributes); ObjectClassInfoBuilder bld = new ObjectClassInfoBuilder(); bld.setType(ObjectClass.ACCOUNT_NAME); bld.addAllAttributeInfo(attributes); ObjectClassInfo objectClassInfo = bld.build(); schemaBuilder.defineObjectClass(objectClassInfo); // Sync is only supported if there is a changelog // try { getLatestSyncToken(ObjectClass.ACCOUNT); } catch (Exception e) { schemaBuilder.removeSupportedObjectClass(SyncOp.class, objectClassInfo); } } //---------------------------------------------------------------------- // RACF Groups // { Set<AttributeInfo> groupAttributes = new HashSet<AttributeInfo>(); // Artificial attr - Sun Idm compat I guess... groupAttributes.add(buildReadonlyAttribute(ATTR_LDAP_ACCOUNTID, String.class)); groupAttributes.add(buildNonupdateAttribute(Name.NAME, String.class, true)); // racfBaseCommon // Represents a commong base class for all RACF profiles. // MAY ( racfAuthorizationDate $ racfOwner $ racfInstallationData $ racfDatasetModel ) groupAttributes.add(AttributeInfoBuilder.build(ATTR_LDAP_OWNER, String.class)); groupAttributes.add(AttributeInfoBuilder.build(ATTR_LDAP_DATA, String.class)); groupAttributes.add(AttributeInfoBuilder.build(ATTR_LDAP_MODEL, String.class)); groupAttributes.add(buildReadonlyAttribute(ATTR_LDAP_AUTHORIZATION_DATE, String.class)); // racfGroup // Represents a RACF GROUP Profile entry // SUP ( racfBaseCommon ) // MUST ( racfid ) // MAY ( racfSuperiorGroup $ racfGroupNoTermUAC $ racfSubGroupName $ racfGroupUserids $ racfGroupUniversal ) ) groupAttributes.add(buildReadonlyAttribute(ATTR_LDAP_ID, String.class)); groupAttributes.add(AttributeInfoBuilder.build(ATTR_LDAP_SUP_GROUP, String.class)); groupAttributes.add(AttributeInfoBuilder.build(ATTR_LDAP_TERM_UACC, String.class)); groupAttributes.add(buildMVROAttribute(ATTR_LDAP_SUB_GROUP, String.class)); groupAttributes.add(buildMVROAttribute(ATTR_LDAP_GROUP_USERIDS, String.class)); groupAttributes.add(AttributeInfoBuilder.build(ATTR_LDAP_UNIVERSAL, String.class)); // racfGroupOvmSegment // Represents the OS/390 OVM Group information portion of a RACF GROUP profile // SUP ( top ) // MAY ( racfOvmGroupId ) ) if (groupObjectClasses.contains("racfGroupOvmSegment")) { groupAttributes.add(AttributeInfoBuilder.build(ATTR_LDAP_OVM_GROUP_ID, String.class)); } // racfGroupOmvsSegment // Represents the OS/390 OMVS Group information portion of a RACF GROUP profile // SUP ( top ) // MAY ( racfOmvsGroupId $ racfOmvsGroupIdKeyword ) ) if (groupObjectClasses.contains("racfGroupOmvsSegment")) { groupAttributes.add(AttributeInfoBuilder.build(ATTR_LDAP_OMVS_GROUP_ID, String.class)); groupAttributes.add(AttributeInfoBuilder.build(ATTR_LDAP_OMVS_GROUP_ID_KEYWORD, String.class)); } // SAFDfpSegment // Represents the SAF DFP portions of a RACF USER or GROUP profile // SUP ( top ) // MAY ( SAFDfpDataApplication $ SAFDfpDataClass $ SAFDfpManagementClass $ SAFDfpStorageClass ) ) if (groupObjectClasses.contains("SAFDfpSegment")) { groupAttributes.add(AttributeInfoBuilder.build(ATTR_LDAP_DPF_DATA_APP, String.class)); groupAttributes.add(AttributeInfoBuilder.build(ATTR_LDAP_DPF_DATA_CLASS, String.class)); groupAttributes.add(AttributeInfoBuilder.build(ATTR_LDAP_DPF_MGMT_CLASS, String.class)); groupAttributes.add(AttributeInfoBuilder.build(ATTR_LDAP_DPF_STORAGE_CLASS, String.class)); } _groupAttributes = AttributeInfoUtil.toMap(groupAttributes); ObjectClassInfoBuilder bld = new ObjectClassInfoBuilder(); bld.setType(RACF_GROUP_NAME); bld.addAllAttributeInfo(groupAttributes); ObjectClassInfo objectClassInfo = bld.build(); schemaBuilder.defineObjectClass(objectClassInfo); // Sync is not supported for Group // schemaBuilder.removeSupportedObjectClass(SyncOp.class, objectClassInfo); // ResolveUsername is not supported for Group // schemaBuilder.removeSupportedObjectClass(ResolveUsernameOp.class, objectClassInfo); } return schemaBuilder.build(); } /** * {@inheritDoc} */ public Schema schema() { if (isLdapConnectionAvailable()) { return ldapSchema(); } else { return clSchema(); } } private AttributeInfo buildMVROAttribute(String name, Class<?> clazz) { AttributeInfoBuilder builder = new AttributeInfoBuilder(); builder.setName(name); builder.setType(clazz); builder.setRequired(false); builder.setMultiValued(true); builder.setCreateable(false); builder.setUpdateable(false); return builder.build(); } private AttributeInfo buildMultivaluedAttribute(String name, Class<?> clazz, boolean required) { AttributeInfoBuilder builder = new AttributeInfoBuilder(); builder.setName(name); builder.setType(clazz); builder.setRequired(required); builder.setMultiValued(true); return builder.build(); } private AttributeInfo buildReadOnlyMultivaluedAttribute(String name, Class<?> clazz) { AttributeInfoBuilder builder = new AttributeInfoBuilder(); builder.setName(name); builder.setType(clazz); builder.setRequired(false); builder.setMultiValued(true); builder.setCreateable(false); builder.setUpdateable(false); return builder.build(); } private AttributeInfo buildNonDefaultMultivaluedAttribute(String name, Class<?> clazz, boolean required) { AttributeInfoBuilder builder = new AttributeInfoBuilder(); builder.setName(name); builder.setType(clazz); builder.setRequired(required); builder.setMultiValued(true); builder.setReturnedByDefault(false); return builder.build(); } private AttributeInfo buildNonupdateAttribute(String name, Class<?> clazz, boolean required) { AttributeInfoBuilder builder = new AttributeInfoBuilder(); builder.setName(name); builder.setType(clazz); builder.setRequired(required); builder.setMultiValued(false); builder.setUpdateable(false); builder.setCreateable(true); builder.setReadable(true); builder.setReturnedByDefault(true); return builder.build(); } private AttributeInfo buildUpdateonlyAttribute(String name, Class<?> clazz, boolean required) { AttributeInfoBuilder builder = new AttributeInfoBuilder(); builder.setName(name); builder.setType(clazz); builder.setRequired(required); builder.setMultiValued(false); builder.setUpdateable(true); builder.setCreateable(false); builder.setReadable(false); builder.setReturnedByDefault(false); return builder.build(); } private AttributeInfo buildNoncreateAttribute(String name, Class<?> clazz, boolean required) { AttributeInfoBuilder builder = new AttributeInfoBuilder(); builder.setName(name); builder.setType(clazz); builder.setRequired(required); builder.setMultiValued(false); builder.setUpdateable(true); builder.setCreateable(false); builder.setReadable(true); builder.setReturnedByDefault(true); return builder.build(); } private AttributeInfo buildReadonlyAttribute(String name, Class<?> clazz) { AttributeInfoBuilder builder = new AttributeInfoBuilder(); builder.setName(name); builder.setType(clazz); builder.setRequired(false); builder.setMultiValued(false); builder.setUpdateable(false); builder.setCreateable(false); builder.setReadable(true); builder.setReturnedByDefault(true); return builder.build(); } private AttributeInfo buildNonDefaultAttribute(String name, Class<?> clazz) { AttributeInfoBuilder builder = new AttributeInfoBuilder(); builder.setName(name); builder.setType(clazz); builder.setRequired(false); builder.setReturnedByDefault(false); builder.setCreateable(true); builder.setUpdateable(true); return builder.build(); } boolean includeInAttributes(ObjectClass objectClass, String attribute, Collection<String> attributesToGet) { if (attribute.equalsIgnoreCase(Name.NAME)) { return true; } if (attributesToGet != null) { return attributesToGet.contains(attribute); } return false; } private boolean isLdapConnectionAvailable() { return _configuration.getLdapUserName() != null; } // public Attribute normalizeAttribute(ObjectClass oclass, Attribute attribute) { // List<Object> values = attribute.getValue(); // List<Object> newValues = new LinkedList<Object>(); // String name = attribute.getName().toUpperCase(); // if (values == null) { // return AttributeBuilder.build(name); // } // for (Object value : values) { // if (value instanceof String) { // if (!LdapUtil.isUidValued(name)) { // newValues.add(( (String) value ).toUpperCase()); // } else { // newValues.add(LdapUtil.createUniformUid(( (String) value ), _configuration.getSuffix())); // } // } else { // newValues.add(value); // } // } // if (attribute instanceof Name) { // return new Name(LdapUtil.createUniformUid((String) newValues.get(0), _configuration.getSuffix())); // } else if (attribute instanceof Uid) { // return new Uid(LdapUtil.createUniformUid((String) newValues.get(0), _configuration.getSuffix())); // } else { // return AttributeBuilder.build(name, newValues); // } // } Attribute convertToBasicASCII(Attribute attribute) { if (_configuration.getConvertToASCII()) { List<Object> values = attribute.getValue(); List<Object> newValues = new LinkedList<Object>(); String name = attribute.getName(); for (Object value : values) { if (value instanceof String) { newValues.add(Normalizer.normalize(( (String) value ), Form.NFD).replaceAll("[\\p{InCombining_Diacritical_Marks}]+", "").replaceAll("[\\P{InBasic_Latin}]+", "_")); } else { newValues.add(value); } } if (!( attribute instanceof Name || attribute instanceof Uid )) { return AttributeBuilder.build(name, newValues); } else { return attribute; } } else { return attribute; } } Long convertFromResumeRevokeFormat(Object value) { try { return _resumeRevokeFormat.parse(value.toString()).getTime(); } catch (ParseException pe) { return null; } } Long convertFromRacfTimestamp(Object value) { if (value == null) { return null; } Matcher matcher = _racfTimestamp.matcher(value.toString()); if (matcher.matches()) { String year = matcher.group(1); String day = matcher.group(2); String hours = matcher.group(3); String minutes = matcher.group(4); String seconds = matcher.group(5); int yearValue = Integer.parseInt(year) + 2000; int dayValue = Integer.parseInt(day); Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.YEAR, yearValue); calendar.set(Calendar.DAY_OF_YEAR, dayValue); calendar.set(Calendar.HOUR_OF_DAY, 0); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); if (hours != null) { int hoursValue = Integer.parseInt(hours); int minutesValue = Integer.parseInt(minutes); int secondsValue = Integer.parseInt(seconds); calendar.set(Calendar.HOUR_OF_DAY, hoursValue); calendar.set(Calendar.MINUTE, minutesValue); calendar.set(Calendar.SECOND, secondsValue); } Date date = calendar.getTime(); return date.getTime(); } else { return null; } } boolean isNullOrEmpty(Attribute attribute) { if (attribute != null) { List<Object> values = attribute.getValue(); if (values == null || values.size() == 0) { return true; } } return false; } void throwErrorIfNull(Map<String, Attribute> attributes, String name) { Attribute attribute = attributes.get(name); if (attribute != null) { throwErrorIfNull(attribute); } } void throwErrorIfNull(Attribute attribute) { if (attribute != null) { List<Object> values = attribute.getValue(); boolean isNull = values == null; if (!isNull) { for (Object value : values) { if (value == null) { isNull = true; break; } } } if (isNull) { throw new IllegalArgumentException(( (RacfConfiguration) getConfiguration() ).getMessage(RacfMessages.NO_VALUE_FOR_ATTRIBUTE, attribute.getName())); } } } void throwErrorIfNullOrEmpty(Attribute attribute) { throwErrorIfNull(attribute); if (attribute != null) { List<Object> values = attribute.getValue(); if (values == null || values.size() == 0) { throw new IllegalArgumentException(( (RacfConfiguration) getConfiguration() ).getMessage(RacfMessages.NO_VALUE_FOR_ATTRIBUTE, attribute.getName())); } } } public void test() { _configuration.validate(); // Ensure that the pool doesn't get reaped during the operation // if (!_configuration.isNoCommandLine()) { ConnectionPool pool = ConnectionPool.getConnectionPool(_configuration, false); try { pool.testAllConnections(); } finally { pool.setReapable(true); } } } public SyncToken getLatestSyncToken(ObjectClass objClass) { if (isLdapConnectionAvailable()) { if (_syncUtil == null) { _syncUtil = new SyncUtil(this); } return _syncUtil.getLatestSyncToken(objClass); } else { throw new UnsupportedOperationException(); } } public void sync(ObjectClass objClass, SyncToken token, SyncResultsHandler handler, OperationOptions options) { if (isLdapConnectionAvailable()) { if (_syncUtil == null) { _syncUtil = new SyncUtil(this); } _syncUtil.sync(objClass, token, handler, options); } else { throw new UnsupportedOperationException(); } } public Uid resolveUsername(ObjectClass objectClass, String username, OperationOptions options) { if (!objectClass.is(ObjectClass.ACCOUNT_NAME)) { throw new IllegalArgumentException(_configuration.getMessage(RacfMessages.UNSUPPORTED_OBJECT_CLASS, objectClass.getObjectClassValue())); } LocalHandler handler = new LocalHandler(); List<String> query = createFilterTranslator(objectClass, options).translate(new EqualsFilter(AttributeBuilder.build(Name.NAME, username))); executeQuery(ObjectClass.ACCOUNT, query.get(0), handler, options); if (!handler.iterator().hasNext()) { throw new UnknownUidException(); } return handler.iterator().next().getUid(); } }