/** * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright (c) 2006 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, add 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]" * * $Id: DiscoEntryHandlerImplUtils.java,v 1.4 2008/06/25 05:49:56 qcheng Exp $ * */ /** * Portions Copyrighted 2012 ForgeRock Inc */ package com.sun.identity.liberty.ws.disco.plugins; import java.io.StringReader; import java.io.StringWriter; import java.util.Collection; 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 javax.xml.transform.stream.StreamSource; import javax.xml.bind.JAXBException; import com.sun.identity.shared.debug.Debug; import com.sun.identity.liberty.ws.disco.common.DiscoConstants; import com.sun.identity.liberty.ws.disco.common.DiscoServiceManager; import com.sun.identity.liberty.ws.disco.common.DiscoUtils; import com.sun.identity.liberty.ws.disco.jaxb.AuthenticateRequesterElement; import com.sun.identity.liberty.ws.disco.jaxb.AuthorizeRequesterElement; import com.sun.identity.liberty.ws.disco.jaxb.AuthenticateSessionContextElement; import com.sun.identity.liberty.ws.disco.jaxb.EncryptResourceIDElement; import com.sun.identity.liberty.ws.disco.jaxb.InsertEntryType; import com.sun.identity.liberty.ws.disco.jaxb.RemoveEntryType; import com.sun.identity.liberty.ws.disco.jaxb.ResourceIDType; import com.sun.identity.liberty.ws.disco.jaxb.ResourceOfferingType; import com.sun.identity.liberty.ws.disco.jaxb.QueryType.RequestedServiceTypeType; import com.sun.identity.liberty.ws.disco.jaxb11.GenerateBearerTokenElement; import com.sun.identity.liberty.ws.disco.plugins.jaxb.DiscoEntryElement; import com.sun.identity.plugin.datastore.DataStoreProvider; import com.sun.identity.saml.common.SAMLUtils; import com.sun.identity.idm.AMIdentity; import com.sun.identity.liberty.ws.interfaces.ResourceIDMapper; import com.sun.identity.shared.xml.XMLUtils; import org.xml.sax.InputSource; public class DiscoEntryHandlerImplUtils { protected static Debug debug = DiscoUtils.debug; /* * Retrieves discovery entries from an user entry. * Used by implementations of SPI DiscoEntryHandler: * DynamicDiscoEntryHandler and * UserDynamicEntryHandler. * @param store DataStoreProvider object. * @param userID user ID. * @param attrName name of the user attribute. * @param discoEntries The results are returned through Map of * entryId to DiscoEntryElement object. * @return true if the results need to be stored; false otherwise. * @throws Exception if SDK errors occurred. */ public static boolean getUserDiscoEntries( DataStoreProvider store, String userID, String attrName, Map discoEntries) throws Exception { boolean needStore = false; Set attr = store.getAttribute(userID, attrName); Iterator i = attr.iterator(); DiscoEntryElement entry = null; String entryID = null; String entryStr = null; while (i.hasNext()) { entryStr = (String) i.next(); try { entry = (DiscoEntryElement) DiscoUtils.getDiscoUnmarshaller().unmarshal( XMLUtils.createSAXSource(new InputSource(new StringReader(entryStr)))); entryID = entry.getResourceOffering().getEntryID(); if ((entryID == null) || (entryID.length() == 0)) { entryID = SAMLUtils.generateID(); entry.getResourceOffering().setEntryID(entryID); needStore = true; } discoEntries.put(entryID, entry); } catch (Exception e) { // this is to skip this miss configured entry // remove it from the store for predictable behavior debug.error( "DiscoEntryHandlerImplUtils.getUserDiscoEntries: wrong " + "format for entry. Removing it from store: " + entryStr); needStore = true; continue; } } return needStore; } /* * Sets discovery entries to user entry. * Used by implementations of SPI DiscoEntryHandler: * UserDiscoEntryHandler and * UserDynamicEntryHandler. * @param store DataStoreProvider object. * @param userID user ID. * @param attrName name of the user attribute to set to. * @param entries Collection of DiscoEntryElement * to be set. * @return true if the operation is successful. */ public static boolean setUserDiscoEntries( DataStoreProvider store, String userID, String attrName, Collection entries) { debug.message("in DiscoEntryHandlerImplUtils.setUserDiscoEntries"); try { Iterator i = entries.iterator(); Set xmlStrings = new HashSet(); StringWriter sw = null; while (i.hasNext()) { sw = new StringWriter(1000); DiscoUtils.getDiscoMarshaller().marshal( ((DiscoEntryElement) i.next()), sw); xmlStrings.add(sw.getBuffer().toString()); } Map map = new HashMap(); map.put(attrName, xmlStrings); store.setAttributes(userID, map); return true; } catch (Exception e) { debug.error( "DiscoEntryHandlerImplUtils.setUserDiscoEntries: Exception", e); return false; } } /* * Finds the matching resource offering according to RequestedServiceType. * Used by DiscoEntryHandlers. * * @param discoEntries all discovery entries * @param reqServiceTypes List of requested service types * @return Map of matching discovery entries. In this map, * key is entryId, value is DiscoEntryElement. */ public static Map getQueryResults( Map discoEntries, List reqServiceTypes) { Map results = null; if ((reqServiceTypes == null) || (reqServiceTypes.size() == 0)) { if (debug.messageEnabled()) { debug.message("DiscoEntryHandlerImplUtils.getQueryResults: " + "no reqServiceTypes"); } results = discoEntries; } else { results = new HashMap(); Iterator i = discoEntries.keySet().iterator(); while (i.hasNext()) { String curKey = (String) i.next(); DiscoEntryElement cur = (DiscoEntryElement) discoEntries.get(curKey); ResourceOfferingType offering = cur.getResourceOffering(); String serviceType = offering.getServiceInstance().getServiceType(); List options = null; if (offering.getOptions() != null) { options = offering.getOptions().getOption(); } Iterator j = reqServiceTypes.iterator(); while (j.hasNext()) { RequestedServiceTypeType curReqType = (RequestedServiceTypeType)j.next(); String requestedServiceType = curReqType.getServiceType(); if (!requestedServiceType.equals(serviceType)) { continue; } List queryOptions = null; if (curReqType.getOptions() != null) { queryOptions = curReqType.getOptions().getOption(); } if (evaluateOptionsRules(queryOptions, options)) { /* code for proxy support if (proxyServiceTypes.contains(serviceType)) { if (this cur is that proxy) { results.add(cur); } else if (requester is the provider) { results.add(cur); } } else { results.add(cur); } */ results.put(curKey, cur); break; } } } } return results; } /** * Performs options matching for queries. The match succeeds * if either list is null or if there is any intersection * between the lists. * @param reqOptions the requested options * @param regOptions the registered options * @return true if the options pass the matching rules */ private static boolean evaluateOptionsRules( List reqOptions, List regOptions ) { if (reqOptions == null || regOptions == null || (reqOptions.size() == 0)) { return true; } Iterator i = reqOptions.iterator(); while (i.hasNext()) { String option = (String) i.next(); if (regOptions.contains(option)) { return true; } } return false; } /* * Removes discovery entries. * Used by implementations of SPI DiscoEntryHandler: * UserDiscoEntryHandler and * UserDynamicEntryHandler. * * @param discoEntriesMap Discovery Entries Map. * @param removes List of entries to be removed. * @return true if the operation is successful. */ public static boolean handleRemoves(Map discoEntriesMap, List removes) { Iterator i = removes.iterator(); RemoveEntryType remove = null; while (i.hasNext()) { remove = (RemoveEntryType) i.next(); if (!discoEntriesMap.containsKey(remove.getEntryID())) { if (debug.messageEnabled()) { debug.message("DiscoEntryHandlerImplUtils.handleRemoves: " + "can not remove entry: " + remove.getEntryID()); } return false; } discoEntriesMap.remove(remove.getEntryID()); } return true; } /* * Adds discovery entries. * Used by implementations of SPI DiscoEntryHandler: * UserDiscoEntryHandler and * UserDynamicEntryHandler. * * @param discoEntriesMap Discovery Entries Map. * @param removes List of entries to be added. * @return true if the operation is successful; false otherwise. */ public static Map handleInserts(Set discoEntries, List inserts) { /* * if support proxy: * look through discoEntries and find all the serviceTypes that have * proxy proxyServiceTypes */ Map insertResults = new HashMap(); insertResults.put(DiscoEntryHandler.STATUS_CODE, DiscoConstants.STATUS_FAILED); Set supportedDirectives = DiscoServiceManager.getSupportedDirectives(); if (debug.messageEnabled()) { debug.message("DiscoEntryHandlerImplUtils.handleInserts: " + "size of supportedDirective is " + supportedDirectives.size()); } Iterator i = inserts.iterator(); InsertEntryType insertEntry = null; DiscoEntryElement de = null; ResourceOfferingType resOff = null; List newEntryIDs = new LinkedList(); while (i.hasNext()) { insertEntry = (InsertEntryType) i.next(); try { de = DiscoUtils.getDiscoEntryFactory(). createDiscoEntryElement(); } catch (JAXBException je) { debug.error( "DiscoEntryHandlerImplUtils.handleInserts: couldn't " + "create DiscoEntry: ", je); return insertResults; } resOff = insertEntry.getResourceOffering(); String newEntryID = SAMLUtils.generateID(); if (debug.messageEnabled()) { debug.message( "DiscoEntryHandlerImplUtils: newEntryID=" + newEntryID); } resOff.setEntryID(newEntryID); newEntryIDs.add(newEntryID); de.setResourceOffering(resOff); List dirs = insertEntry.getAny(); if ((dirs != null) && !dirs.isEmpty()) { Iterator j = dirs.iterator(); while (j.hasNext()) { Object dir = j.next(); if (dir instanceof AuthenticateRequesterElement) { if (!supportedDirectives.contains( DiscoConstants.AUTHN_DIRECTIVE) ) { debug.error("Directive AuthenticateRequester is " + "not supported."); return insertResults; } } else if (dir instanceof AuthorizeRequesterElement) { if (!supportedDirectives.contains( DiscoConstants.AUTHZ_DIRECTIVE) ) { debug.error("Directive AuthorizeRequester is " + "not supported."); return insertResults; } } else if (dir instanceof AuthenticateSessionContextElement) { if (!supportedDirectives.contains( DiscoConstants.SESSION_DIRECTIVE) ) { debug.error("Directive AuthenticateSessionContext " + "is not supported."); return insertResults; } } else if (dir instanceof EncryptResourceIDElement) { if (!supportedDirectives.contains( DiscoConstants.ENCRYPT_DIRECTIVE)) { debug.error("Directive EncryptResourceID " + "is not supported."); return insertResults; } } else if (dir instanceof GenerateBearerTokenElement) { if (!supportedDirectives.contains( DiscoConstants.BEARER_DIRECTIVE) ) { debug.error("Directive GenerateBearerToken " + "is not supported."); return insertResults; } } else { debug.error("Directive " + dir + " is not supported."); return insertResults; } } de.getAny().addAll(dirs); } if (!discoEntries.add(de)) { debug.error( "DiscoEntryHandlerImplUtils.handleInserts: couldn't " + "add DiscoEntry to Set."); return insertResults; } } insertResults.put(DiscoEntryHandler.STATUS_CODE, DiscoConstants.STATUS_OK); insertResults.put(DiscoEntryHandler.NEW_ENTRY_IDS, newEntryIDs); return insertResults; } /** * This is used by the global disocvery service handler to retrieve * the resource offerings registered at the realm, org, role etc. */ public static void getGlobalDiscoEntries(AMIdentity amIdentity, String attrName, Map discoEntries, String userID) throws Exception { Map map = amIdentity.getServiceAttributes( "sunIdentityServerDiscoveryService"); Set attr = (Set)map.get(attrName); if (attr == null || attr.isEmpty()) { debug.error("DiscoEntryHandlerImplUtils.getServiceDiscoEntries: " + "The resource offerings are not available"); return; } if(debug.messageEnabled()) { debug.message("DiscoEntryHandlerImplUtils.getServiceDiscoEntries: " + attr); } Iterator j = attr.iterator(); String entryStr = null; String resIDValue = null; DiscoEntryElement entry = null; ResourceIDType resID = null; ResourceOfferingType resOff = null; String entryID = null; String providerID = null; while (j.hasNext()) { entryStr = (String) j.next(); try { entry = (DiscoEntryElement) DiscoUtils.getDiscoUnmarshaller().unmarshal( XMLUtils.createSAXSource(new InputSource(new StringReader(entryStr)))); resOff = entry.getResourceOffering(); entryID = resOff.getEntryID(); if(entryID == null) { entryID = SAMLUtils.generateID(); resOff.setEntryID(entryID); } ResourceIDType rid = resOff.getResourceID(); if((rid == null) || (rid.getValue() == null) || (rid.getValue().equals(""))) { com.sun.identity.liberty.ws.disco.jaxb.ObjectFactory discoFac = new com.sun.identity.liberty.ws.disco.jaxb.ObjectFactory(); resID = discoFac.createResourceIDType(); resID.setValue(DiscoConstants.IMPLIED_RESOURCE); resOff.setResourceID(resID); } entry.setResourceOffering(resOff); discoEntries.put(entryID, entry); } catch (Exception e) { debug.error("DiscoEntryHandlerImplUtils.getServiceDiscoEntries:" + " Exception for getting entry: " + entryStr + ":", e); continue; } } } /** * Registers the discovery service resource offerings to the AMIdentity * * This is used by the global disocvery service handler to register * the resource offerings to the realm, org, role etc. * @param amIdentity the idrepo object that the resource offerings are * being set. * @param attrName the discovery service attribute name where the disco * entries are being stored. * @param entries the list of discovery services that needs to be set. * @return true if successfully set the entries. */ public static boolean setGlobalDiscoEntries( AMIdentity amIdentity, String attrName, Collection entries) { try { Iterator i = entries.iterator(); Set xmlStrings = new HashSet(); String entryId = null; StringWriter sw = null; while (i.hasNext()) { sw = new StringWriter(1000); DiscoUtils.getDiscoMarshaller().marshal( ((DiscoEntryElement)i.next()), sw); xmlStrings.add(sw.getBuffer().toString()); } Map map = new HashMap(); map.put(attrName, xmlStrings); amIdentity.modifyService("sunIdentityServerDiscoveryService", map); amIdentity.store(); return true; } catch (Exception e) { debug.error("DiscoEntryHandlerImplUtils.setServiceDiscoEntries:" + " Exception", e); return false; } } }