/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2009 Sun Microsystems Inc. All Rights Reserved * * The contents of this file are subject to the terms * of the Common Development and Distribution License * (the License). You may not use this file except in * compliance with the License. * * You can obtain a copy of the License at * https://opensso.dev.java.net/public/CDDLv1.0.html or * opensso/legal/CDDLv1.0.txt * See the License for the specific language governing * permission and limitations under the License. * * When distributing Covered Code, include this CDDL * Header Notice in each file and include the License file * at opensso/legal/CDDLv1.0.txt. * If applicable, addReferral the following below the CDDL Header, * with the fields enclosed by brackets [] replaced by * your own identifying information: * "Portions Copyrighted [year] [name of copyright owner]" * * Portions Copyrighted 2014-2015 ForgeRock AS. * * $Id: OpenSSOPolicyDataStore.java,v 1.7 2010/01/08 22:20:47 veiming Exp $ */ package com.sun.identity.entitlement.opensso; import com.iplanet.sso.SSOException; import com.iplanet.sso.SSOToken; import com.sun.identity.entitlement.ApplicationPrivilege; import com.sun.identity.entitlement.ApplicationPrivilegeManager; import com.sun.identity.entitlement.EntitlementConfiguration; import com.sun.identity.entitlement.EntitlementException; import com.sun.identity.entitlement.IPrivilege; import com.sun.identity.entitlement.PolicyDataStore; import com.sun.identity.entitlement.Privilege; import com.sun.identity.entitlement.PrivilegeIndexStore; import com.sun.identity.entitlement.PrivilegeManager; import com.sun.identity.entitlement.ReferralPrivilege; import com.sun.identity.policy.Policy; import com.sun.identity.policy.PolicyException; import com.sun.identity.policy.PolicyManager; import com.sun.identity.security.AdminTokenAction; import com.sun.identity.shared.xml.XMLUtils; import com.sun.identity.sm.DNMapper; import com.sun.identity.sm.SMSEntry; import com.sun.identity.sm.SMSException; import com.sun.identity.sm.ServiceConfig; import com.sun.identity.sm.ServiceConfigManager; import java.io.ByteArrayInputStream; import java.security.AccessController; import java.text.MessageFormat; import java.util.HashMap; import java.util.HashSet; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.logging.Level; import javax.security.auth.Subject; import org.w3c.dom.Document; import org.w3c.dom.Node; /** */ public class OpenSSOPolicyDataStore extends PolicyDataStore { private static final String POLICY_XML = "xmlpolicy"; private static final String REALM_DN_TEMPLATE = "ou=Policies,ou=default,ou=OrganizationConfig,ou=1.0,ou=" + PolicyManager.POLICY_SERVICE_NAME + ",ou=services,{0}"; private static Subject dsameUserSubject; private static SSOToken dsameUserToken; static { dsameUserToken = (SSOToken) AccessController.doPrivileged( AdminTokenAction.getInstance()); dsameUserSubject = SubjectUtils.createSubject(dsameUserToken); } public void addPolicy(Subject subject, String realm, Privilege privilege) throws EntitlementException { // Delegation to applications is currently not configurable, passing super admin (see AME-4959) ApplicationPrivilegeManager applPrivilegeMgr = ApplicationPrivilegeManager.getInstance(realm, PrivilegeManager.superAdminSubject); if (!applPrivilegeMgr.hasPrivilege(privilege, ApplicationPrivilege.Action.MODIFY)) { throw new EntitlementException(326); } String name = ""; try { Object policy = PrivilegeUtils.privilegeToPolicyObject( realm, privilege); name = PrivilegeUtils.getPolicyName(policy); if (policy instanceof Policy || policy instanceof com.sun.identity.entitlement.xacml3.core.Policy ) { String dn = getPolicyDistinguishedName(realm, name); if (SMSEntry.checkIfEntryExists(dn, dsameUserToken)) { throw new EntitlementException(EntitlementException.POLICY_ALREADY_EXISTS); } createParentNode(dsameUserToken, realm); SMSEntry s = new SMSEntry(dsameUserToken, dn); Map> map = new HashMap>(); Set setServiceID = new HashSet(2); map.put(SMSEntry.ATTR_SERVICE_ID, setServiceID); setServiceID.add("NamedPolicy"); Set setObjectClass = new HashSet(4); map.put(SMSEntry.ATTR_OBJECTCLASS, setObjectClass); setObjectClass.add(SMSEntry.OC_TOP); setObjectClass.add(SMSEntry.OC_SERVICE_COMP); Set setValue = new HashSet(2); map.put(SMSEntry.ATTR_KEYVAL, setValue); setValue.add(POLICY_XML + "=" + PrivilegeUtils.policyToXML(policy)); s.setAttributes(map); String[] logParams = {DNMapper.orgNameToRealmName(realm), name}; OpenSSOLogger.log(OpenSSOLogger.LogLevel.MESSAGE, Level.INFO, "ATTEMPT_ADD_PRIVILEGE", logParams, subject); s.save(); OpenSSOLogger.log(OpenSSOLogger.LogLevel.MESSAGE, Level.INFO, "SUCCEEDED_ADD_PRIVILEGE", logParams, subject); PrivilegeIndexStore pis = PrivilegeIndexStore.getInstance( dsameUserSubject, realm); Set privileges = new HashSet(); privileges.add(privilege); pis.add(privileges); } else { PrivilegeManager.debug.error( "OpenSSOPolicyDataStore.addPolicy: unknown class " + policy.getClass().getName()); } } catch (PolicyException e) { String[] logParams = {DNMapper.orgNameToRealmName(realm), name, e.getMessage()}; OpenSSOLogger.log(OpenSSOLogger.LogLevel.ERROR, Level.INFO, "FAILED_ADD_PRIVILEGE", logParams, subject); Object[] params = {name}; throw new EntitlementException(202, params, e); } catch (SSOException e) { String[] logParams = {DNMapper.orgNameToRealmName(realm), name, e.getMessage()}; OpenSSOLogger.log(OpenSSOLogger.LogLevel.ERROR, Level.INFO, "FAILED_ADD_PRIVILEGE", logParams, subject); Object[] params = {name}; throw new EntitlementException(202, params, e); } catch (SMSException e) { String[] logParams = {DNMapper.orgNameToRealmName(realm), name, e.getMessage()}; OpenSSOLogger.log(OpenSSOLogger.LogLevel.ERROR, Level.INFO, "FAILED_ADD_PRIVILEGE", logParams, subject); Object[] params = {name}; throw new EntitlementException(202, params, e); } } private void createParentNode( SSOToken adminToken, String realm ) throws SSOException, SMSException { ServiceConfig orgConf = getOrgConfig(adminToken, realm); Set subConfigNames = orgConf.getSubConfigNames(); if (!subConfigNames.contains(PolicyDataStore.POLICIES)) { orgConf.addSubConfig(PolicyDataStore.POLICIES, PolicyDataStore.POLICIES, 0, null); } } private ServiceConfig getOrgConfig(SSOToken adminToken, String realm) throws SMSException, SSOException { ServiceConfigManager mgr = new ServiceConfigManager( PolicyManager.POLICY_SERVICE_NAME, adminToken); ServiceConfig orgConf = mgr.getOrganizationConfig(realm, null); if (orgConf == null) { mgr.createOrganizationConfig(realm, null); orgConf = mgr.getOrganizationConfig(realm, null); } return orgConf; } public Object getPolicy(Subject adminSubject, String realm, String name) throws EntitlementException { SSOToken adminToken = SubjectUtils.getSSOToken(adminSubject); if (adminToken == null) { Object[] params = {name}; throw new EntitlementException(209, params); } String dn = getPolicyDistinguishedName(realm, name); if (!SMSEntry.checkIfEntryExists(dn, adminToken)) { Object[] params = {name}; throw new EntitlementException(203, params); } try { SMSEntry s = new SMSEntry(adminToken, dn); Map> map = s.getAttributes(); Set xml = map.get(SMSEntry.ATTR_KEYVAL); String strXML = xml.iterator().next(); if (strXML.startsWith(POLICY_XML)) { strXML = strXML.substring(POLICY_XML.length() +1); } return createPolicy(adminToken, realm, strXML); } catch (SSOException ex) { Object[] params = {name}; throw new EntitlementException(204, params, ex); } catch (SMSException ex) { Object[] params = {name}; throw new EntitlementException(204, params, ex); } catch (Exception ex) { Object[] params = {name}; throw new EntitlementException(204, params, ex); } } /** * Attempts to find a legacy policy with the given policy name. As a legacy policy with multiple rules will be * translated into multiple Privilege objects named {@code policy1_rule1}, we may not be able to find the legacy * policy with the same name. In this case, we repeatedly strip off {@code _XXX} suffixes from the policy name to * try to find the matching legacy policy. If we still cannot find such a policy, then we return {@code null}. * * @param adminToken the SSOToken to use when querying to see if a policy exists. * @param realm the realm in which the policy exists. * @param policyName the initial name of the policy. * @return the DN of the matching legacy policy, or {@code null} if no match was found. */ private String findLegacyPolicyDn(SSOToken adminToken, String realm, String policyName) { String dn = getPolicyDistinguishedName(realm, policyName); int idx = policyName.length(); while (!SMSEntry.checkIfEntryExists(dn, adminToken)) { debug("Unable to find policy with name %s using DN %s", policyName, dn); idx = policyName.lastIndexOf('_', idx-1); if (idx >= 0) { dn = getPolicyDistinguishedName(realm, policyName.substring(0, idx)); } else { return null; } } return dn; } private static void debug(final String format, final Object...args) { if (PrivilegeManager.debug.messageEnabled()) { PrivilegeManager.debug.message(String.format(Locale.US, "OpenSSOPolicyDataStore: " + format, args)); } } public ReferralPrivilege getReferral( Subject adminSubject, String realm, String name ) throws EntitlementException { SSOToken adminToken = (adminSubject == PrivilegeManager.superAdminSubject) ? dsameUserToken : SubjectUtils.getSSOToken(adminSubject); if (adminToken == null) { Object[] params = {name}; throw new EntitlementException(262, params); } String dn = getPolicyDistinguishedName(realm, name); if (!SMSEntry.checkIfEntryExists(dn, adminToken)) { Object[] params = {name}; throw new EntitlementException(263, params); } try { SMSEntry s = new SMSEntry(adminToken, dn); Map> map = s.getAttributes(); Set set = map.get(SMSEntry.ATTR_KEYVAL); String xml = set.iterator().next(); if (xml.startsWith(POLICY_XML)) { xml = xml.substring(POLICY_XML.length() +1); } Set privileges = PrivilegeUtils.policyToPrivileges( createPolicy(adminToken, realm, xml)); return (ReferralPrivilege)privileges.iterator().next(); } catch (SSOException ex) { Object[] params = {name}; throw new EntitlementException(204, params, ex); } catch (SMSException ex) { Object[] params = {name}; throw new EntitlementException(204, params, ex); } catch (Exception ex) { Object[] params = {name}; throw new EntitlementException(204, params, ex); } } private Object createPolicy(SSOToken adminToken, String realm, String xml) throws Exception, SSOException, PolicyException { Object policy = null; if (xml.startsWith("xmlpolicy=")) { xml = xml.substring(10); } Document doc = XMLUtils.getXMLDocument( new ByteArrayInputStream(xml.getBytes("UTF8"))); if (EntitlementConfiguration.getInstance( SubjectUtils.createSubject(adminToken), "/").xacmlPrivilegeEnabled()) { //TODO: create xacml policy from xml document } else { PolicyManager pm = new PolicyManager(adminToken, realm); Node rootNode = XMLUtils.getRootNode(doc, PolicyManager.POLICY_ROOT_NODE); policy = new Policy(pm, rootNode); } return policy; } public void removePrivilege(Subject subject, String realm, Privilege privilege) throws EntitlementException { SSOToken adminToken = SubjectUtils.getSSOToken(subject); String name = privilege.getName(); if (adminToken == null) { Object[] params = {name}; throw new EntitlementException(211, params); } // Delegation to applications is currently not configurable, passing super admin (see AME-4959) ApplicationPrivilegeManager applPrivilegeMgr = ApplicationPrivilegeManager.getInstance(realm, PrivilegeManager.superAdminSubject); if (!applPrivilegeMgr.hasPrivilege(privilege, ApplicationPrivilege.Action.MODIFY)) { throw new EntitlementException(326); } try { String[] logParams = {DNMapper.orgNameToRealmName(realm), name}; OpenSSOLogger.log(OpenSSOLogger.LogLevel.MESSAGE, Level.INFO, "ATTEMPT_REMOVE_PRIVILEGE", logParams, subject); // Remove from privilege index store first PrivilegeIndexStore pis = PrivilegeIndexStore.getInstance( dsameUserSubject, realm); pis.delete(name); // Only remove from legacy policy store if the policy still exists. This can happen if an old policy // had multiple rules (= multiple privileges in new store) and one of the new privileges for that policy // has been deleted, which deletes the entire legacy policy. String dn = findLegacyPolicyDn(dsameUserToken, realm, name); if (dn != null) { SMSEntry s = new SMSEntry(dsameUserToken, dn); s.delete(); } else { debug("Unable to find legacy policy for privilege %s in realm %s", name, realm); } OpenSSOLogger.log(OpenSSOLogger.LogLevel.MESSAGE, Level.INFO, "SUCCEEDED_REMOVE_PRIVILEGE", logParams, subject); } catch (SSOException ex) { String[] logParams = {DNMapper.orgNameToRealmName(realm), name, ex.getMessage()}; OpenSSOLogger.log(OpenSSOLogger.LogLevel.ERROR, Level.INFO, "FAILED_REMOVE_PRIVILEGE", logParams, subject); Object[] params = {name}; throw new EntitlementException(205, params, ex); } catch (SMSException ex) { String[] logParams = {DNMapper.orgNameToRealmName(realm), name, ex.getMessage()}; OpenSSOLogger.log(OpenSSOLogger.LogLevel.ERROR, Level.INFO, "FAILED_REMOVE_PRIVILEGE", logParams, subject); Object[] params = {name}; throw new EntitlementException(205, params, ex); } } private static String getPolicyDistinguishedName(String realm, String name) { return "ou=" + name + "," + getStoreBaseDN(realm); } private static String getStoreBaseDN(String realm) { Object[] args = {DNMapper.orgNameToDN(realm)}; return MessageFormat.format(REALM_DN_TEMPLATE, args); } public void addReferral( Subject subject, String realm, ReferralPrivilege referral) throws EntitlementException { String name = referral.getName(); String dn = getPolicyDistinguishedName(realm, name); SSOToken adminToken = SubjectUtils.getSSOToken(subject); if (adminToken == null) { Object[] params = {name}; throw new EntitlementException(260, params); } // Delegation to applications is currently not configurable, passing super admin (see AME-4959) ApplicationPrivilegeManager applPrivilegeMgr = ApplicationPrivilegeManager.getInstance(realm, PrivilegeManager.superAdminSubject); if (!applPrivilegeMgr.hasPrivilege(referral, ApplicationPrivilege.Action.MODIFY)) { throw new EntitlementException(326); } try { createParentNode(dsameUserToken, realm); SMSEntry s = new SMSEntry(dsameUserToken, dn); Map> map = new HashMap>(); Set setServiceID = new HashSet(2); map.put(SMSEntry.ATTR_SERVICE_ID, setServiceID); setServiceID.add("NamedPolicy"); Set setObjectClass = new HashSet(4); map.put(SMSEntry.ATTR_OBJECTCLASS, setObjectClass); setObjectClass.add(SMSEntry.OC_TOP); setObjectClass.add(SMSEntry.OC_SERVICE_COMP); Set setValue = new HashSet(2); map.put(SMSEntry.ATTR_KEYVAL, setValue); Policy p = PrivilegeUtils.referralPrivilegeToPolicy( realm, referral); setValue.add(POLICY_XML + "=" +p.toXML()); s.setAttributes(map); String[] logParams = {DNMapper.orgNameToRealmName(realm), name}; OpenSSOLogger.log(OpenSSOLogger.LogLevel.MESSAGE, Level.INFO, "ATTEMPT_ADD_REFERRAL", logParams, subject); s.save(); OpenSSOLogger.log(OpenSSOLogger.LogLevel.MESSAGE, Level.INFO, "SUCCEEDED_ADD_REFERRAL", logParams, subject); PrivilegeIndexStore pis = PrivilegeIndexStore.getInstance( dsameUserSubject, realm); Set tmp = new HashSet(); tmp.add(referral); pis.add(tmp); } catch (PolicyException e) { String[] logParams = {DNMapper.orgNameToRealmName(realm), name, e.getMessage()}; OpenSSOLogger.log(OpenSSOLogger.LogLevel.ERROR, Level.INFO, "FAILED_ADD_REFERRAL", logParams, subject); Object[] params = {name}; throw new EntitlementException(261, params, e); } catch (SSOException e) { String[] logParams = {DNMapper.orgNameToRealmName(realm), name, e.getMessage()}; OpenSSOLogger.log(OpenSSOLogger.LogLevel.ERROR, Level.INFO, "FAILED_ADD_REFERRAL", logParams, subject); Object[] params = {name}; throw new EntitlementException(261, params, e); } catch (SMSException e) { String[] logParams = {DNMapper.orgNameToRealmName(realm), name, e.getMessage()}; OpenSSOLogger.log(OpenSSOLogger.LogLevel.ERROR, Level.INFO, "FAILED_ADD_REFERRAL", logParams, subject); Object[] params = {name}; throw new EntitlementException(261, params, e); } } public void removeReferral( Subject subject, String realm, ReferralPrivilege referral ) throws EntitlementException { SSOToken adminToken = SubjectUtils.getSSOToken(subject); String name = referral.getName(); if (adminToken == null) { Object[] params = {name}; throw new EntitlementException(266, params); } // Delegation to applications is currently not configurable, passing super admin (see AME-4959) ApplicationPrivilegeManager applPrivilegeMgr = ApplicationPrivilegeManager.getInstance(realm, PrivilegeManager.superAdminSubject); if (!applPrivilegeMgr.hasPrivilege(referral, ApplicationPrivilege.Action.MODIFY)) { throw new EntitlementException(326); } String dn = getPolicyDistinguishedName(realm, name); if (!SMSEntry.checkIfEntryExists(dn, dsameUserToken)) { Object[] params = {name}; throw new EntitlementException(263, params); } try { String[] logParams = {DNMapper.orgNameToRealmName(realm), name}; OpenSSOLogger.log(OpenSSOLogger.LogLevel.MESSAGE, Level.INFO, "ATTEMPT_REMOVE_REFERRAL", logParams, subject); SMSEntry s = new SMSEntry(dsameUserToken, dn); s.delete(); OpenSSOLogger.log(OpenSSOLogger.LogLevel.MESSAGE, Level.INFO, "SUCCEEDED_REMOVE_REFERRAL", logParams, subject); PrivilegeIndexStore pis = PrivilegeIndexStore.getInstance( dsameUserSubject, realm); pis.deleteReferral(name); } catch (SSOException ex) { String[] logParams = {DNMapper.orgNameToRealmName(realm), name, ex.getMessage()}; OpenSSOLogger.log(OpenSSOLogger.LogLevel.ERROR, Level.INFO, "FAILED_REMOVE_REFERRAL", logParams, subject); Object[] params = {name}; throw new EntitlementException(205, params, ex); } catch (SMSException ex) { String[] logParams = {DNMapper.orgNameToRealmName(realm), name, ex.getMessage()}; OpenSSOLogger.log(OpenSSOLogger.LogLevel.ERROR, Level.INFO, "FAILED_REMOVE_REFERRAL", logParams, subject); Object[] params = {name}; throw new EntitlementException(205, params, ex); } } }