/* * 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, 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: PrivilegeChangeNotifier.java,v 1.5 2010/01/07 00:19:11 veiming Exp $ * * Portions Copyrighted 2014-2015 ForgeRock AS. */ package com.sun.identity.entitlement; import com.sun.identity.common.HttpURLConnectionManager; import com.sun.identity.entitlement.interfaces.ResourceName; import java.io.BufferedReader; import java.io.IOException; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.SocketTimeoutException; import java.net.URL; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.security.auth.Subject; import org.forgerock.openam.entitlement.PolicyConstants; import org.json.JSONException; import org.json.JSONObject; public class PrivilegeChangeNotifier { private static PrivilegeChangeNotifier instance = new PrivilegeChangeNotifier(); private static int POOL_SIZE = 5; private static int HTTP_TIMEOUT = 1000; private static int NUM_RETRY = 3; private static int RETRY_INTERVAL = 3000; static { EntitlementConfiguration ec = EntitlementConfiguration.getInstance( PolicyConstants.SUPER_ADMIN_SUBJECT, "/"); POOL_SIZE = getConfiguration(ec, "privilege-notifier-threadpool-size", 5); HTTP_TIMEOUT = getConfiguration(ec, "privilege-notifier-conn-timeout", 1000); NUM_RETRY = getConfiguration(ec, "privilege-notifier-retries", 3); RETRY_INTERVAL = getConfiguration(ec, "privilege-notifier-duration-between-retries", 3000); } private static int getConfiguration( EntitlementConfiguration ec, String name, int defaultVal ) { Set values = ec.getConfiguration(name); if ((values == null) || values.isEmpty()) { return defaultVal; } try { return Integer.parseInt(values.iterator().next()); } catch (NumberFormatException e) { PolicyConstants.DEBUG.error( "PrivilegeChangeNotifier.getConfiguration: attribute name=" + name, e); return defaultVal; } } private static EntitlementThreadPool thrdPool = new EntitlementThreadPool(POOL_SIZE); private PrivilegeChangeNotifier() { } public static PrivilegeChangeNotifier getInstance() { return instance; } public void notify( Subject adminSubject, String realm, String applicationName, String privilegeName, Set resources) { try { Set listeners = ListenerManager.getInstance().getListeners(adminSubject); Set urls = new HashSet(); for (EntitlementListener l : listeners) { if (toSendNotification(adminSubject, realm, l, applicationName, resources)) { urls.add(l.getUrl()); } } String json = toJSONString(realm, privilegeName, resources); for (URL url : urls) { thrdPool.submit(new Task(adminSubject, url.toString(), json)); } } catch (JSONException e) { PolicyConstants.DEBUG.error("PrivilegeChangeNotifier.notify", e); } catch (EntitlementException e) { PolicyConstants.DEBUG.error("PrivilegeChangeNotifier.notify", e); } } private boolean toSendNotification( Subject adminSubject, String realm, EntitlementListener l, String applicationName, Set resources) throws EntitlementException { Map> map = l.getMapAppToRes(); for (String appName : map.keySet()) { if (appName.equals(applicationName)) { Set res = map.get(appName); if ((res == null) || res.isEmpty()) { return true; } Application app = ApplicationManager.getApplication( PolicyConstants.SUPER_ADMIN_SUBJECT, realm, appName); ResourceName resourceComp = app.getResourceComparator(); for (String r : res) { if (doesResourceMatch(resourceComp, r, resources)) { return true; } } } } return false; } private boolean doesResourceMatch( ResourceName resourceComp, String resource, Set resources) { for (String r : resources) { ResourceMatch match = resourceComp.compare(r, resource, true); if (match.equals(ResourceMatch.EXACT_MATCH) || match.equals(ResourceMatch.SUPER_RESOURCE_MATCH) || match.equals(ResourceMatch.WILDCARD_MATCH)) { return true; } } return false; } private static String toJSONString( String realm, String privilegeName, Set resources) throws JSONException { JSONObject jo = new JSONObject(); jo.put("realm", realm); jo.put("privilegeName", privilegeName); jo.put("resources", resources); return jo.toString(); } public class Task implements Runnable { private Subject adminSubject; private String url; private String json; Task( Subject adminSubject, String url, String json ) { this.adminSubject = adminSubject; this.url = url; this.json = json; } public void run() { int cnt = 0; boolean done = false; while ((cnt++ < NUM_RETRY) && !done) { done = postRequest(); if (!done) { try { Thread.sleep(RETRY_INTERVAL); } catch (InterruptedException e) { //ignore } } } if (!done) { try { ListenerManager.getInstance(). removeListener(adminSubject, url); } catch (EntitlementException ex) { PolicyConstants.DEBUG.error( "PrivilegeChangeNotifier.Task.run", ex); } } } private boolean postRequest() { OutputStreamWriter wr = null; BufferedReader rd = null; try { try { URL urlObj = new URL(url); HttpURLConnection conn = HttpURLConnectionManager.getConnection(urlObj); conn.setConnectTimeout(HTTP_TIMEOUT); conn.setDoOutput(true); wr = new OutputStreamWriter( conn.getOutputStream()); wr.write(json); wr.flush(); int status = conn.getResponseCode(); return (status == HttpURLConnection.HTTP_OK); } catch (SocketTimeoutException e) { PolicyConstants.DEBUG.error( "PrivilegeChangeNotifier.Task.postRequest", e); return false; } catch (IOException e) { PolicyConstants.DEBUG.error( "PrivilegeChangeNotifier.Task.postRequest", e); return false; } } finally { try { if (wr != null) { wr.close(); } if (rd != null) { rd.close(); } } catch (IOException e) { //ignore } } } } }