http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/src/main/java/com/att/research/xacml/rest/XACMLPapServlet.java ---------------------------------------------------------------------- diff --git a/openaz-xacml-pap-rest/src/main/java/com/att/research/xacml/rest/XACMLPapServlet.java b/openaz-xacml-pap-rest/src/main/java/com/att/research/xacml/rest/XACMLPapServlet.java new file mode 100755 index 0000000..e57a36b --- /dev/null +++ b/openaz-xacml-pap-rest/src/main/java/com/att/research/xacml/rest/XACMLPapServlet.java @@ -0,0 +1,1529 @@ +/* + * AT&T - PROPRIETARY + * THIS FILE CONTAINS PROPRIETARY INFORMATION OF + * AT&T AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN + * ACCORDANCE WITH APPLICABLE AGREEMENTS. + * + * Copyright (c) 2013 AT&T Knowledge Ventures + * Unpublished and Not for Publication + * All Rights Reserved + */ +package com.att.research.xacml.rest; + + +import com.att.research.xacml.api.pap.*; +import com.att.research.xacml.std.pap.StdPDP; +import com.att.research.xacml.std.pap.StdPDPGroup; +import com.att.research.xacml.std.pap.StdPDPItemSetChangeNotifier.StdItemSetChangeListener; +import com.att.research.xacml.std.pap.StdPDPStatus; +import com.att.research.xacml.util.FactoryException; +import com.att.research.xacml.util.XACMLProperties; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.base.Splitter; +import org.apache.commons.io.IOUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.annotation.WebInitParam; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.*; +import java.util.*; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * Servlet implementation class XacmlPapServlet + * + * + * @author pameladragosh + */ +@WebServlet( + description = "Implements the XACML PAP RESTful API.", + urlPatterns = { "/" }, + loadOnStartup=1, + initParams = { + @WebInitParam(name = "XACML_PROPERTIES_NAME", value = "xacml.pap.properties", description = "The location of the properties file holding configuration information.") + }) + +public class XACMLPapServlet extends HttpServlet implements StdItemSetChangeListener, Runnable { + private static final long serialVersionUID = 1L; + private static final Log logger = LogFactory.getLog(XACMLPapServlet.class); + + /* + * + * papEngine - This is our engine workhorse that manages the PDP Groups and Nodes. + */ + private PAPEngine papEngine = null; + + /* + * This PAP instance's own URL. + * + * Need this when creating URLs to send to the PDPs so they can GET the Policy files from this process. + */ + private static String papURL = null; + + /* + * List of Admin Console URLs. + * Used to send notifications when configuration changes. + * + * The CopyOnWriteArrayList *should* protect from concurrency errors. + * This list is seldom changed but often read, so the costs of this approach make sense. + */ + private static final CopyOnWriteArrayList<String> adminConsoleURLStringList = new CopyOnWriteArrayList<String>(); + + /* + * This thread may be invoked upon startup to initiate sending PDP policy/pip configuration when + * this servlet starts. Its configurable by the admin. + */ + private Thread initiateThread = null; + + /* + // The heartbeat thread. + */ + private static Heartbeat heartbeat = null; + private static Thread heartbeatThread = null; + + /** + * @see HttpServlet#HttpServlet() + */ + public XACMLPapServlet() { + super(); + } + + /** + * @see Servlet#init(ServletConfig) + */ + public void init(ServletConfig config) throws ServletException { + try { + // + // Initialize + // + XACMLRest.xacmlInit(config); + // + // Load the properties + // + XACMLRest.loadXacmlProperties(null, null); + // + // Load our PAP engine, first create a factory + // + PAPEngineFactory factory = PAPEngineFactory.newInstance(XACMLProperties.getProperty(XACMLProperties.PROP_PAP_PAPENGINEFACTORY)); + // + // The factory knows how to go about creating a PAP Engine + // + this.papEngine = factory.newEngine(); + // + // we are about to call the PDPs and give them their configuration. + // To do that we need to have the URL of this PAP so we can construct the Policy file URLs + // + XACMLPapServlet.papURL = XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_URL); + // + // Sanity check that a URL was defined somewhere, its essential. + // + // How to check that its valid? We can validate the form, but since we are in the init() method we + // are not fully loaded yet so we really couldn't ping ourself to see if the URL will work. One + // will have to look for errors in the PDP logs to determine if they are failing to initiate a + // request to this servlet. + // + if (XACMLPapServlet.papURL == null) { + throw new PAPException("The property " + XACMLRestProperties.PROP_PAP_URL + " is not valid: " + XACMLPapServlet.papURL); + } + // + // Configurable - have the PAP servlet initiate sending the latest PDP policy/pip configuration + // to all its known PDP nodes. + // + // Note: parseBoolean will return false if there is no property defined. This is fine for a default. + // + if (Boolean.parseBoolean(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_INITIATE_PDP_CONFIG))) { + this.initiateThread = new Thread(this); + this.initiateThread.start(); + } + // + // After startup, the PAP does Heartbeats to each of the PDPs periodically + // + XACMLPapServlet.heartbeat = new Heartbeat(this.papEngine); + XACMLPapServlet.heartbeatThread = new Thread(XACMLPapServlet.heartbeat); + XACMLPapServlet.heartbeatThread.start(); + } catch (FactoryException | PAPException e) { + logger.error("Failed to create engine", e); + throw new ServletException ("PAP not initialized; error: "+e); + } catch (Exception e) { + logger.error("Failed to create engine - unexpected error: ", e); + throw new ServletException ("PAP not initialized; unexpected error: "+e); } + } + + /** + * Thread used only during PAP startup to initiate change messages to all known PDPs. + * This must be on a separate thread so that any GET requests from the PDPs during this update can be serviced. + */ + @Override + public void run() { + // + // send the current configuration to all the PDPs that we know about + // + changed(); + } + + + /** + * @see Servlet#destroy() + * + * Depending on how this servlet is run, we may or may not care about cleaning up the resources. + * For now we assume that we do care. + */ + public void destroy() { + // + // Make sure our threads are destroyed + // + if (XACMLPapServlet.heartbeatThread != null) { + // + // stop the heartbeat + // + try { + if (XACMLPapServlet.heartbeat != null) { + XACMLPapServlet.heartbeat.terminate(); + } + XACMLPapServlet.heartbeatThread.interrupt(); + XACMLPapServlet.heartbeatThread.join(); + } catch (InterruptedException e) { + logger.error(e); + } + } + if (this.initiateThread != null) { + try { + this.initiateThread.interrupt(); + this.initiateThread.join(); + } catch (InterruptedException e) { + logger.error(e); + } + } + } + + /** + * + * Called by: + * - PDP nodes to register themselves with the PAP, and + * - Admin Console to make changes in the PDP Groups. + * + * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response) + */ + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + try { + + XACMLRest.dumpRequest(request); + + // since getParameter reads the content string, explicitly get the content before doing that. + // Simply getting the inputStream seems to protect it against being consumed by getParameter. + request.getInputStream(); + + // + // Is this from the Admin Console? + // + String groupId = request.getParameter("groupId"); + if (groupId != null) { + // + // this is from the Admin Console, so handle separately + // + doACPost(request, response, groupId); + return; + } + + // + // Request is from a PDP. + // It is coming up and asking for its config + // + + // + // Get the PDP's ID + // + String id = this.getPDPID(request); + logger.info("doPost from: " + id); + // + // Get the PDP Object + // + PDP pdp = this.papEngine.getPDP(id); + // + // Is it known? + // + if (pdp == null) { + logger.info("Unknown PDP: " + id); + try { + this.papEngine.newPDP(id, this.papEngine.getDefaultGroup(), id, "Registered on first startup"); + } catch (NullPointerException | PAPException e) { + logger.error("Failed to create new PDP", e); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage()); + return; + } + // get the PDP we just created + pdp = this.papEngine.getPDP(id); + if (pdp == null) { + String message = "Failed to create new PDP for id: " + id; + logger.error(message); + response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, message); + return; + } + } + // + // Get the PDP's Group + // + PDPGroup group = this.papEngine.getPDPGroup(pdp); + if (group == null) { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "PDP not associated with any group, even the default"); + return; + } + // + // Determine what group the PDP node is in and get + // its policy/pip properties. + // + Properties policies = group.getPolicyProperties(); + Properties pipconfig = group.getPipConfigProperties(); + // + // Get the current policy/pip configuration that the PDP has + // + Properties pdpProperties = new Properties(); + pdpProperties.load(request.getInputStream()); + logger.info("PDP Current Properties: " + pdpProperties.toString()); + logger.info("Policies: " + (policies != null ? policies.toString() : "null")); + logger.info("Pip config: " + (pipconfig != null ? pipconfig.toString() : "null")); + // + // Validate the node's properties + // + boolean isCurrent = this.isPDPCurrent(policies, pipconfig, pdpProperties); + // + // Send back current configuration + // + if (isCurrent == false) { + // + // Tell the PDP we are sending back the current policies/pip config + // + logger.info("PDP configuration NOT current."); + if (policies != null) { + // + // Put URL's into the properties in case the PDP needs to + // retrieve them. + // + this.populatePolicyURL(request.getRequestURL(), policies); + // + // Copy the properties to the output stream + // + policies.store(response.getOutputStream(), ""); + } + if (pipconfig != null) { + // + // Copy the properties to the output stream + // + pipconfig.store(response.getOutputStream(), ""); + } + // + // We are good - and we are sending them information + // + response.setStatus(HttpServletResponse.SC_OK); +//TODO - Correct? + setPDPSummaryStatus(pdp, PDPStatus.Status.OUT_OF_SYNCH); + } else { + // + // Tell them they are good + // + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + + //TODO - Correct? + setPDPSummaryStatus(pdp, PDPStatus.Status.UP_TO_DATE); + + } + // + // tell the AC that something changed + // + notifyAC(); + } catch (PAPException e) { + logger.debug("POST exception: " + e, e); + response.sendError(500, e.getMessage()); + return; + } + } + + + /** + * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response) + */ + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + try { + XACMLRest.dumpRequest(request); + + // Is this from the Admin Console? + String groupId = request.getParameter("groupId"); + if (groupId != null) { + // this is from the Admin Console, so handle separately + doACGet(request, response, groupId); + return; + } + // + // Get the PDP's ID + // + String id = this.getPDPID(request); + logger.info("doGet from: " + id); + // + // Get the PDP Object + // + PDP pdp = this.papEngine.getPDP(id); + // + // Is it known? + // + if (pdp == null) { + // + // Check if request came from localhost + // + String message = "Unknown PDP: " + id + " from " + request.getRemoteHost() + " us: " + request.getLocalAddr(); + logger.info(message); + if (request.getRemoteHost().equals("localhost") || + request.getRemoteHost().equals("127.0.0.1") || + request.getRemoteHost().equals(request.getLocalAddr())) { + // + // Return status information - basically all the groups + // + Set<PDPGroup> groups = papEngine.getPDPGroups(); + + // convert response object to JSON and include in the response + ObjectMapper mapper = new ObjectMapper(); + mapper.writeValue(response.getOutputStream(), groups); + response.setHeader("content-type", "application/json"); + response.setStatus(HttpServletResponse.SC_OK); + return; + } + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, message); + return; + } + // + // Get the PDP's Group + // + PDPGroup group = this.papEngine.getPDPGroup(pdp); + if (group == null) { + String message = "No group associated with pdp " + pdp.getId(); + logger.warn(message); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, message); + return; + } + // + // Which policy do they want? + // + String policyId = request.getParameter("id"); + if (policyId == null) { + String message = "Did not specify an id for the policy"; + logger.warn(message); + response.sendError(HttpServletResponse.SC_NOT_FOUND, message); + return; + } + PDPPolicy policy = group.getPolicy(policyId); + if (policy == null) { + String message = "Unknown policy: " + policyId; + logger.warn(message); + response.sendError(HttpServletResponse.SC_NOT_FOUND, message); + return; + } + // + // Get its stream + // + try (InputStream is = policy.getStream(); OutputStream os = response.getOutputStream()) { + // + // Send the policy back + // + IOUtils.copy(is, os); + + response.setStatus(HttpServletResponse.SC_OK); + } catch (PAPException e) { + String message = "Failed to open policy id " + policyId; + logger.error(message); + response.sendError(HttpServletResponse.SC_NOT_FOUND, message); + } + } catch (PAPException e) { + logger.error("GET exception: " + e, e); + response.sendError(500, e.getMessage()); + return; + } + } + + protected String getPDPID(HttpServletRequest request) { + String pdpURL = request.getHeader(XACMLRestProperties.PROP_PDP_HTTP_HEADER_ID); + if (pdpURL == null || pdpURL.isEmpty()) { + // + // Should send back its port for identification + // + logger.warn("PDP did not send custom header"); + pdpURL = ""; + } + return pdpURL; + } + + private boolean isPDPCurrent(Properties policies, Properties pipconfig, Properties pdpProperties) { + String localRootPolicies = policies.getProperty(XACMLProperties.PROP_ROOTPOLICIES); + String localReferencedPolicies = policies.getProperty(XACMLProperties.PROP_REFERENCEDPOLICIES); + if (localRootPolicies == null || localReferencedPolicies == null) { + logger.warn("Missing property on PAP server: RootPolicies="+localRootPolicies+" ReferencedPolicies="+localReferencedPolicies); + return false; + } + // + // Compare the policies and pipconfig properties to the pdpProperties + // + try { + // + // the policy properties includes only xacml.rootPolicies and + // xacml.referencedPolicies without any .url entries + // + Properties pdpPolicies = XACMLProperties.getPolicyProperties(pdpProperties, false); + Properties pdpPipConfig = XACMLProperties.getPipProperties(pdpProperties); + if (localRootPolicies.equals(pdpPolicies.getProperty(XACMLProperties.PROP_ROOTPOLICIES)) && + localReferencedPolicies.equals(pdpPolicies.getProperty(XACMLProperties.PROP_REFERENCEDPOLICIES)) && + pdpPipConfig.equals(pipconfig)) { + // + // The PDP is current + // + return true; + } + } catch (Exception e) { + // we get here if the PDP did not include either xacml.rootPolicies or xacml.pip.engines, + // or if there are policies that do not have a corresponding ".url" property. + // Either of these cases means that the PDP is not up-to-date, so just drop-through to return false. + } + return false; + } + + private void populatePolicyURL(StringBuffer urlPath, Properties policies) { + String lists[] = new String[2]; + lists[0] = policies.getProperty(XACMLProperties.PROP_ROOTPOLICIES); + lists[1] = policies.getProperty(XACMLProperties.PROP_REFERENCEDPOLICIES); + for (String list : lists) { + if (list != null && list.isEmpty() == false) { + for (String id : Splitter.on(',').trimResults().omitEmptyStrings().split(list)) { + String url = urlPath + "?id=" + id; + logger.info("Policy URL for " + id + ": " + url); + policies.setProperty(id + ".url", url); + } + } + } + } + + + /** + * @see HttpServlet#doPut(HttpServletRequest request, HttpServletResponse response) + */ + protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + XACMLRest.dumpRequest(request); + // + // since getParameter reads the content string, explicitly get the content before doing that. + // Simply getting the inputStream seems to protect it against being consumed by getParameter. + // + request.getInputStream(); + // + // See if this is Admin Console registering itself with us + // + String acURLString = request.getParameter("adminConsoleURL"); + if (acURLString != null) { + // + // remember this Admin Console for future updates + // + if ( ! adminConsoleURLStringList.contains(acURLString)) { + adminConsoleURLStringList.add(acURLString); + } + if (logger.isDebugEnabled()) { + logger.debug("Admin Console registering with URL: " + acURLString); + } + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + return; + } + // + // Is this some other operation from the Admin Console? + // + String groupId = request.getParameter("groupId"); + if (groupId != null) { + // + // this is from the Admin Console, so handle separately + // + doACPut(request, response, groupId); + return; + } + // + // We do not expect anything from anywhere else. + // This method is here in case we ever need to support other operations. + // + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Request does not have groupId"); + } + + /** + * @see HttpServlet#doDelete(HttpServletRequest request, HttpServletResponse response) + */ + protected void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + XACMLRest.dumpRequest(request); + // + // Is this from the Admin Console? + // + String groupId = request.getParameter("groupId"); + if (groupId != null) { + // + // this is from the Admin Console, so handle separately + // + doACDelete(request, response, groupId); + return; + } + // + // We do not expect anything from anywhere else. + // This method is here in case we ever need to support other operations. + // + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Request does not have groupId"); + } + // + // Admin Console request handling + // + + /** + * Requests from the Admin Console to GET info about the Groups and PDPs + * + * @param request + * @param response + * @param groupId + * @throws ServletException + * @throws java.io.IOException + */ + private void doACGet(HttpServletRequest request, HttpServletResponse response, String groupId) throws ServletException, IOException { + try { + String parameterDefault = request.getParameter("default"); + String pdpId = request.getParameter("pdpId"); + String pdpGroup = request.getParameter("getPDPGroup"); + if ("".equals(groupId)) { + // request IS from AC but does not identify a group by name + if (parameterDefault != null) { + // Request is for the Default group (whatever its id) + PDPGroup group = papEngine.getDefaultGroup(); + + // convert response object to JSON and include in the response + ObjectMapper mapper = new ObjectMapper(); + mapper.writeValue(response.getOutputStream(), group); + + if (logger.isDebugEnabled()) { + logger.debug("GET Default group req from '" + request.getRequestURL() + "'"); + } + response.setStatus(HttpServletResponse.SC_OK); + response.setHeader("content-type", "application/json"); + response.getOutputStream().close(); + return; + + } else if (pdpId != null) { + // Request is related to a PDP + if (pdpGroup == null) { + // Request is for the PDP itself + // Request is for the (unspecified) group containing a given PDP + PDP pdp = papEngine.getPDP(pdpId); + + // convert response object to JSON and include in the response + ObjectMapper mapper = new ObjectMapper(); + mapper.writeValue(response.getOutputStream(), pdp); + + if (logger.isDebugEnabled()) { + logger.debug("GET pdp '" + pdpId + "' req from '" + request.getRequestURL() + "'"); + } + response.setStatus(HttpServletResponse.SC_OK); + response.setHeader("content-type", "application/json"); + response.getOutputStream().close(); + return; + + } else { + // Request is for the (unspecified) group containing a given PDP + PDP pdp = papEngine.getPDP(pdpId); + PDPGroup group = papEngine.getPDPGroup(pdp); + + // convert response object to JSON and include in the response + ObjectMapper mapper = new ObjectMapper(); + mapper.writeValue(response.getOutputStream(), group); + + if (logger.isDebugEnabled()) { + logger.debug("GET PDP '" + pdpId + "' Group req from '" + request.getRequestURL() + "'"); + } + response.setStatus(HttpServletResponse.SC_OK); + response.setHeader("content-type", "application/json"); + response.getOutputStream().close(); + return; + } + + } else { + // request is for top-level properties about all groups + Set<PDPGroup> groups = papEngine.getPDPGroups(); + + // convert response object to JSON and include in the response + ObjectMapper mapper = new ObjectMapper(); + mapper.writeValue(response.getOutputStream(), groups); + +//TODO +// In "notification" section, ALSO need to tell AC about other changes (made by other ACs)?' +//TODO add new PDP notification (or just "config changed" notification) in appropriate place + if (logger.isDebugEnabled()) { + logger.debug("GET All groups req"); + } + response.setStatus(HttpServletResponse.SC_OK); + response.setHeader("content-type", "application/json"); + response.getOutputStream().close(); + return; + } + } + + // for all other GET operations the group must exist before the operation can be done + PDPGroup group = papEngine.getGroup(groupId); + if (group == null) { + logger.error("Unknown groupId '" + groupId + "'"); + response.sendError(HttpServletResponse.SC_NOT_FOUND, "Unknown groupId '" + groupId +"'"); + return; + } + + + // Figure out which request this is based on the parameters + String policyId = request.getParameter("policyId"); + + if (policyId != null) { +// // retrieve a policy +// PDPPolicy policy = papEngine.getPDPPolicy(policyId); +// +// // convert response object to JSON and include in the response +// ObjectMapper mapper = new ObjectMapper(); +// mapper.writeValue(response.getOutputStream(), pdp); +// +// logger.debug("GET group '" + group.getId() + "' req from '" + request.getRequestURL() + "'"); +// response.setStatus(HttpServletResponse.SC_OK); +// response.setHeader("content-type", "application/json"); +// response.getOutputStream().close(); +// return; + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "GET Policy not implemented"); + + } else { + // No other parameters, so return the identified Group + + // convert response object to JSON and include in the response + ObjectMapper mapper = new ObjectMapper(); + mapper.writeValue(response.getOutputStream(), group); + + if (logger.isDebugEnabled()) { + logger.debug("GET group '" + group.getId() + "' req from '" + request.getRequestURL() + "'"); + } + response.setStatus(HttpServletResponse.SC_OK); + response.setHeader("content-type", "application/json"); + response.getOutputStream().close(); + return; + } + + // + // Currently there are no other GET calls from the AC. + // The AC uses the "GET All Groups" operation to fill its local cache and uses that cache for all other GETs without calling the PAP. + // Other GETs that could be called: + // Specific Group (groupId=<groupId>) + // A Policy (groupId=<groupId> policyId=<policyId>) + // A PDP (groupId=<groupId> pdpId=<pdpId>) + + //TODO - implement other GET operations if needed + + logger.error("UNIMPLEMENTED "); + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "UNIMPLEMENTED"); + } catch (PAPException e) { + logger.error("AC Get exception: " + e, e); + response.sendError(500, e.getMessage()); + return; + } + + } + + + /** + * Requests from the Admin Console for operations not on single specific objects + * + * @param request + * @param response + * @param groupId + * @throws ServletException + * @throws java.io.IOException + */ + private void doACPost(HttpServletRequest request, HttpServletResponse response, String groupId) throws ServletException, IOException { + try { + String groupName = request.getParameter("groupName"); + String groupDescription = request.getParameter("groupDescription"); + if (groupName != null && groupDescription != null) { + // Args: group=<groupId> groupName=<name> groupDescription=<description> <= create a new group + String unescapedName = URLDecoder.decode(groupName, "UTF-8"); + String unescapedDescription = URLDecoder.decode(groupDescription, "UTF-8"); + try { + papEngine.newGroup(unescapedName, unescapedDescription); + } catch (Exception e) { + logger.error("Unable to create new group: " + e.getLocalizedMessage()); + response.sendError(500, "Unable to create new group '" + groupId + "'"); + return; + } + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + if (logger.isDebugEnabled()) { + logger.debug("New Group '" + groupId + "' created"); + } + // tell the Admin Consoles there is a change + notifyAC(); + // new group by definition has no PDPs, so no need to notify them of changes + return; + } + + // for all remaining POST operations the group must exist before the operation can be done + PDPGroup group = papEngine.getGroup(groupId); + if (group == null) { + logger.error("Unknown groupId '" + groupId + "'"); + response.sendError(HttpServletResponse.SC_NOT_FOUND, "Unknown groupId '" + groupId +"'"); + return; + } + + // determine the operation needed based on the parameters in the request + if (request.getParameter("policyId") != null) { + // Args: group=<groupId> policy=<policyId> <= copy file + // copy a policy from the request contents into a file in the group's directory on this machine + String policyId = request.getParameter("policyId"); + try { + ((StdPDPGroup) group).copyPolicyToFile(policyId, request.getInputStream()); + } catch (Exception e) { + String message = "Policy '" + policyId + "' not copied to group '" + groupId +"': " + e; + logger.error(message); + response.sendError(500, message); + return; + } + // policy file copied ok + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + if (logger.isDebugEnabled()) { + logger.debug("policy '" + policyId + "' copied to directory for group '" + groupId + "'"); + } + return; + + } else if (request.getParameter("default") != null) { + // Args: group=<groupId> default=true <= make default + // change the current default group to be the one identified in the request. + // + // This is a POST operation rather than a PUT "update group" because of the side-effect that the current default group is also changed. + // It should never be the case that multiple groups are currently marked as the default, but protect against that anyway. + try { + papEngine.SetDefaultGroup(group); + } catch (Exception e) { + logger.error("Unable to set group: " + e.getLocalizedMessage()); + response.sendError(500, "Unable to set group '" + groupId + "' to default"); + return; + } + + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + if (logger.isDebugEnabled()) { + logger.debug("Group '" + groupId + "' set to be default"); + } + // Notify the Admin Consoles that something changed + // For now the AC cannot handle anything more detailed than the whole set of PDPGroups, so just notify on that +//TODO - Future: FIGURE OUT WHAT LEVEL TO NOTIFY: 2 groups or entire set - currently notify AC to update whole configuration of all groups + notifyAC(); + // This does not affect any PDPs in the existing groups, so no need to notify them of this change + return; + + } else if (request.getParameter("pdpId") != null) { + // Args: group=<groupId> pdpId=<pdpId> <= move PDP to group + String pdpId = request.getParameter("pdpId"); + PDP pdp = papEngine.getPDP(pdpId); + + PDPGroup originalGroup = papEngine.getPDPGroup(pdp); + + papEngine.movePDP(pdp, group); + + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + if (logger.isDebugEnabled()) { + logger.debug("PDP '" + pdp.getId() +"' moved to group '" + group.getId() + "' set to be default"); + } + + // update the status of both the original group and the new one + ((StdPDPGroup)originalGroup).resetStatus(); + ((StdPDPGroup)group).resetStatus(); + + // Notify the Admin Consoles that something changed + // For now the AC cannot handle anything more detailed than the whole set of PDPGroups, so just notify on that + notifyAC(); + // Need to notify the PDP that it's config may have changed + pdpChanged(pdp); + return; + + + } + } catch (PAPException e) { + logger.error("AC POST exception: " + e, e); + response.sendError(500, e.getMessage()); + return; + } + } + + /** + * Requests from the Admin Console to create new items or update existing ones + * + * @param request + * @param response + * @param groupId + * @throws ServletException + * @throws java.io.IOException + */ + private void doACPut(HttpServletRequest request, HttpServletResponse response, String groupId) throws ServletException, IOException { + try { + + + // for PUT operations the group may or may not need to exist before the operation can be done + PDPGroup group = papEngine.getGroup(groupId); + + // determine the operation needed based on the parameters in the request + + // for remaining operations the group must exist before the operation can be done + if (group == null) { + logger.error("Unknown groupId '" + groupId + "'"); + response.sendError(HttpServletResponse.SC_NOT_FOUND, "Unknown groupId '" + groupId +"'"); + return; + } + if (request.getParameter("policy") != null) { + // group=<groupId> policy=<policyId> contents=policy file <= Create new policy file in group dir, or replace it if it already exists (do not touch properties) + //TODO - currently this is done by the AC, but it should be done here by getting the policy file out of the contents and saving to disk + logger.error("PARTIALLY IMPLEMENTED!!! ACTUAL CHANGES SHOULD BE MADE BY PAP SERVLET!!! "); + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + return; + } else if (request.getParameter("pdpId") != null) { + // ARGS: group=<groupId> pdpId=<pdpId/URL> <= create a new PDP or Update an Existing one + + String pdpId = request.getParameter("pdpId"); + + // get the request content into a String + String json = null; + // read the inputStream into a buffer (trick found online scans entire input looking for end-of-file) + java.util.Scanner scanner = new java.util.Scanner(request.getInputStream()); + scanner.useDelimiter("\\A"); + json = scanner.hasNext() ? scanner.next() : ""; + scanner.close(); + logger.info("JSON request from AC: " + json); + + // convert Object sent as JSON into local object + ObjectMapper mapper = new ObjectMapper(); + + Object objectFromJSON = mapper.readValue(json, StdPDP.class); + + if (pdpId == null || + objectFromJSON == null || + ! (objectFromJSON instanceof StdPDP) || + ((StdPDP)objectFromJSON).getId() == null || + ! ((StdPDP)objectFromJSON).getId().equals(pdpId)) { + logger.error("PDP new/update had bad input. pdpId=" + pdpId + " objectFromJSON="+objectFromJSON); + response.sendError(500, "Bad input, pdpid="+pdpId+" object="+objectFromJSON); + } + StdPDP pdp = (StdPDP) objectFromJSON; + + if (papEngine.getPDP(pdpId) == null) { + // this is a request to create a new PDP object + papEngine.newPDP(pdp.getId(), group, pdp.getName(), pdp.getDescription()); + } else { + // this is a request to update the pdp + papEngine.updatePDP(pdp); + } + + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + if (logger.isDebugEnabled()) { + logger.debug("PDP '" + pdpId + "' created/updated"); + } + + // adjust the group's state including the new PDP + ((StdPDPGroup)group).resetStatus(); + + // tell the Admin Consoles there is a change + notifyAC(); + // this might affect the PDP, so notify it of the change + pdpChanged(pdp); + return; + } else if (request.getParameter("pipId") != null) { + // group=<groupId> pipId=<pipEngineId> contents=pip properties <= add a PIP to pip config, or replace it if it already exists (lenient operation) + //TODO + logger.error("UNIMPLEMENTED "); + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "UNIMPLEMENTED"); + return; + } else { + // Assume that this is an update of an existing PDP Group + // ARGS: group=<groupId> <= Update an Existing Group + + // get the request content into a String + String json = null; + // read the inputStream into a buffer (trick found online scans entire input looking for end-of-file) + java.util.Scanner scanner = new java.util.Scanner(request.getInputStream()); + scanner.useDelimiter("\\A"); + json = scanner.hasNext() ? scanner.next() : ""; + scanner.close(); + logger.info("JSON request from AC: " + json); + + // convert Object sent as JSON into local object + ObjectMapper mapper = new ObjectMapper(); + + Object objectFromJSON = mapper.readValue(json, StdPDPGroup.class); + + if (objectFromJSON == null || + ! (objectFromJSON instanceof StdPDPGroup) || + ! ((StdPDPGroup)objectFromJSON).getId().equals(group.getId())) { + logger.error("Group update had bad input. id=" + group.getId() + " objectFromJSON="+objectFromJSON); + response.sendError(500, "Bad input, id="+group.getId() +" object="+objectFromJSON); + } + + // The Path on the PAP side is not carried on the RESTful interface with the AC + // (because it is local to the PAP) + // so we need to fill that in before submitting the group for update + ((StdPDPGroup)objectFromJSON).setDirectory(((StdPDPGroup)group).getDirectory()); + + papEngine.updateGroup((StdPDPGroup)objectFromJSON); + + + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + if (logger.isDebugEnabled()) { + logger.debug("Group '" + group.getId() + "' updated"); + } + // tell the Admin Consoles there is a change + notifyAC(); + // Group changed, which might include changing the policies + groupChanged(group); + return; + } + } catch (PAPException e) { + logger.error("AC PUT exception: " + e, e); + response.sendError(500, e.getMessage()); + return; + } + } + + /** + * Requests from the Admin Console to delete/remove items + * + * @param request + * @param response + * @param groupId + * @throws ServletException + * @throws java.io.IOException + */ + private void doACDelete(HttpServletRequest request, HttpServletResponse response, String groupId) throws ServletException, IOException { + try { + // for all DELETE operations the group must exist before the operation can be done + PDPGroup group = papEngine.getGroup(groupId); + if (group == null) { + logger.error("Unknown groupId '" + groupId + "'"); + response.sendError(HttpServletResponse.SC_NOT_FOUND, "Unknown groupId '" + groupId +"'"); + return; + } + // determine the operation needed based on the parameters in the request + if (request.getParameter("policy") != null) { + // group=<groupId> policy=<policyId> [delete=<true|false>] <= delete policy file from group + //TODO + logger.error("UNIMPLEMENTED "); + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "UNIMPLEMENTED"); + return; + } else if (request.getParameter("pdpId") != null) { + // ARGS: group=<groupId> pdpId=<pdpId> <= delete PDP + String pdpId = request.getParameter("pdpId"); + PDP pdp = papEngine.getPDP(pdpId); + + papEngine.removePDP(pdp); + + // adjust the status of the group, which may have changed when we removed this PDP + ((StdPDPGroup)group).resetStatus(); + + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + notifyAC(); + + // update the PDP and tell it that it has NO Policies (which prevents it from serving PEP Requests) + pdpChanged(pdp); + return; + } else if (request.getParameter("pipId") != null) { + // group=<groupId> pipId=<pipEngineId> <= delete PIP config for given engine + //TODO + logger.error("UNIMPLEMENTED "); + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "UNIMPLEMENTED"); + return; + } else { + // ARGS: group=<groupId> movePDPsToGroupId=<movePDPsToGroupId> <= delete a group and move all its PDPs to the given group + String moveToGroupId = request.getParameter("movePDPsToGroupId"); + PDPGroup moveToGroup = null; + if (moveToGroupId != null) { + moveToGroup = papEngine.getGroup(moveToGroupId); + } + + // get list of PDPs in the group being deleted so we can notify them that they got changed + Set<PDP> movedPDPs = new HashSet<PDP>(); + movedPDPs.addAll(group.getPdps()); + + // do the move/remove + papEngine.removeGroup(group, moveToGroup); + + response.setStatus(HttpServletResponse.SC_NO_CONTENT); + notifyAC(); + // notify any PDPs in the removed set that their config may have changed + for (PDP pdp : movedPDPs) { + pdpChanged(pdp); + } + return; + } + + } catch (PAPException e) { + logger.error("AC DELETE exception: " + e, e); + response.sendError(500, e.getMessage()); + return; + } + } + + // + // Heartbeat thread - periodically check on PDPs' status + // + + /** + * Heartbeat with all known PDPs. + * + * Implementation note: + * + * The PDPs are contacted Sequentially, not in Parallel. + * + * If we did this in parallel using multiple threads we would simultaneously use + * - 1 thread and + * - 1 connection + * for EACH PDP. + * This could become a resource problem since we already use multiple threads and connections for updating the PDPs + * when user changes occur. + * Using separate threads can also make it tricky dealing with timeouts on PDPs that are non-responsive. + * + * The Sequential operation does a heartbeat request to each PDP one at a time. + * This has the flaw that any PDPs that do not respond will hold up the entire heartbeat sequence until they timeout. + * If there are a lot of non-responsive PDPs and the timeout is large-ish (the default is 20 seconds) + * it could take a long time to cycle through all of the PDPs. + * That means that this may not notice a PDP being down in a predictable time. + * + * @author glenngriffin + * + */ + private class Heartbeat implements Runnable { + private PAPEngine papEngine; + private Set<PDP> pdps = new HashSet<PDP>(); + private int heartbeatInterval; + private int heartbeatTimeout; + + public volatile boolean isRunning = false; + + public synchronized boolean isRunning() { + return this.isRunning; + } + + public synchronized void terminate() { + this.isRunning = false; + } + + public Heartbeat(PAPEngine engine) { + this.papEngine = engine; + this.heartbeatInterval = Integer.parseInt(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_HEARTBEAT_INTERVAL, "10000")); + this.heartbeatTimeout = Integer.parseInt(XACMLProperties.getProperty(XACMLRestProperties.PROP_PAP_HEARTBEAT_TIMEOUT, "10000")); + } + + @Override + public void run() { + // + // Set ourselves as running + // + synchronized(this) { + this.isRunning = true; + } + HashMap<String, URL> idToURLMap = new HashMap<String, URL>(); + try { + while (this.isRunning()) { + // Wait the given time + Thread.sleep(heartbeatInterval); + + // get the list of PDPs (may have changed since last time) + pdps.clear(); + synchronized(papEngine) { + try { + for (PDPGroup g : papEngine.getPDPGroups()) { + for (PDP p : g.getPdps()) { + pdps.add(p); + } + } + } catch (PAPException e) { + logger.error("Heartbeat unable to read PDPs from PAPEngine: " + e.getMessage(), e); + } + } + // + // Check for shutdown + // + if (this.isRunning() == false) { + logger.info("isRunning is false, getting out of loop."); + break; + } + + // try to get the summary status from each PDP + boolean changeSeen = false; + for (PDP pdp : pdps) { + // + // Check for shutdown + // + if (this.isRunning() == false) { + logger.info("isRunning is false, getting out of loop."); + break; + } + // the id of the PDP is its url (though we add a query parameter) + URL pdpURL = idToURLMap.get(pdp.getId()); + if (pdpURL == null) { + // haven't seen this PDP before + String fullURLString = null; + try { + fullURLString = pdp.getId() + "?type=hb"; + pdpURL = new URL(fullURLString); + idToURLMap.put(pdp.getId(), pdpURL); + } catch (MalformedURLException e) { + logger.error("PDP id '" + fullURLString + "' is not a valid URL: " + e, e); + continue; + } + } + + // Do a GET with type HeartBeat + String newStatus = ""; + + HttpURLConnection connection = null; + try { + + // + // Open up the connection + // + connection = (HttpURLConnection)pdpURL.openConnection(); + // + // Setup our method and headers + // + connection.setRequestMethod("GET"); + connection.setConnectTimeout(heartbeatTimeout); + // + // Do the connect + // + connection.connect(); + if (connection.getResponseCode() == 204) { + newStatus = connection.getHeaderField(XACMLRestProperties.PROP_PDP_HTTP_HEADER_HB); + if (logger.isDebugEnabled()) { + logger.debug("Heartbeat '" + pdp.getId() + "' status='" + newStatus + "'"); + } + } else { + // anything else is an unexpected result + newStatus = PDPStatus.Status.UNKNOWN.toString(); + logger.error("Heartbeat connect response code " + connection.getResponseCode() + ": " + pdp.getId()); + } + } catch (UnknownHostException e) { + newStatus = PDPStatus.Status.NO_SUCH_HOST.toString(); + logger.error("Heartbeat '" + pdp.getId() + "' NO_SUCH_HOST"); + } catch (SocketTimeoutException e) { + newStatus = PDPStatus.Status.CANNOT_CONNECT.toString(); + logger.error("Heartbeat '" + pdp.getId() + "' connection timeout: " + e ); + } catch (ConnectException e) { + newStatus = PDPStatus.Status.CANNOT_CONNECT.toString(); + logger.error("Heartbeat '" + pdp.getId() + "' cannot connect: " + e ); + } catch (Exception e) { + newStatus = PDPStatus.Status.UNKNOWN.toString(); + logger.error("Heartbeat '" + pdp.getId() + "' connect exception: " + e, e); + } finally { + // cleanup the connection + connection.disconnect(); + } + + if ( ! pdp.getStatus().getStatus().toString().equals(newStatus)) { + if (logger.isDebugEnabled()) { + logger.debug("previous status='" + pdp.getStatus().getStatus()+"' new Status='" + newStatus + "'"); + } + try { + setPDPSummaryStatus(pdp, newStatus); + } catch (PAPException e) { + logger.error("Unable to set state for PDP '" + pdp.getId() + "': " + e, e); + } + changeSeen = true; + } + + } + // + // Check for shutdown + // + if (this.isRunning() == false) { + logger.info("isRunning is false, getting out of loop."); + break; + } + + // if any of the PDPs changed state, tell the ACs to update + if (changeSeen) { + notifyAC(); + } + + } + } catch (InterruptedException e) { + logger.error("Heartbeat interrupted. Shutting down"); + this.terminate(); + } + } + } + + + // + // HELPER to change Group status when PDP status is changed + // + // (Must NOT be called from a method that is synchronized on the papEngine or it may deadlock) + // + + private void setPDPSummaryStatus(PDP pdp, PDPStatus.Status newStatus) throws PAPException { + setPDPSummaryStatus(pdp, newStatus.toString()); + } + + private void setPDPSummaryStatus(PDP pdp, String newStatus) throws PAPException { + synchronized(papEngine) { + StdPDPStatus status = (StdPDPStatus)pdp.getStatus(); + status.setStatus(PDPStatus.Status.valueOf(newStatus)); + ((StdPDP)pdp).setStatus(status); + + // now adjust the group + StdPDPGroup group = (StdPDPGroup)papEngine.getPDPGroup(pdp); + // if the PDP was just deleted it may transiently exist but not be in a group + if (group != null) { + group.resetStatus(); + } + } + } + + + // + // Callback methods telling this servlet to notify PDPs of changes made by the PAP StdEngine + // in the PDP group directories + // + + @Override + public void changed() { + // all PDPs in all groups need to be updated/sync'd + Set<PDPGroup> groups; + try { + groups = papEngine.getPDPGroups(); + } catch (PAPException e) { + logger.error("getPDPGroups failed: " + e.getLocalizedMessage()); + throw new RuntimeException("Unable to get Groups: " + e); + } + for (PDPGroup group : groups) { + groupChanged(group); + } + } + + @Override + public void groupChanged(PDPGroup group) { + // all PDPs within one group need to be updated/sync'd + for (PDP pdp : group.getPdps()) { + pdpChanged(pdp); + } + } + + @Override + public void pdpChanged(PDP pdp) { + // kick off a thread to do an event notification for each PDP. + // This needs to be on a separate thread so that PDPs that do not respond (down, non-existent, etc) + // do not block the PSP response to the AC, which would freeze the GUI until all PDPs sequentially respond or time-out. + Thread t = new Thread(new UpdatePDPThread(pdp)); + t.start(); + } + + private class UpdatePDPThread implements Runnable { + private PDP pdp; + + // remember which PDP to notify + public UpdatePDPThread(PDP pdp) { + this.pdp = pdp; + } + + public void run() { + // send the current configuration to one PDP + HttpURLConnection connection = null; + try { + + // + // the Id of the PDP is its URL + // + if (logger.isDebugEnabled()) { + logger.debug("creating url for id '" + pdp.getId() + "'"); + } + //TODO - currently always send both policies and pips. Do we care enough to add code to allow sending just one or the other? + //TODO (need to change "cache=", implying getting some input saying which to change) + URL url = new URL(pdp.getId() + "?cache=all"); + + // + // Open up the connection + // + connection = (HttpURLConnection)url.openConnection(); + // + // Setup our method and headers + // + connection.setRequestMethod("PUT"); + // connection.setRequestProperty("Accept", "text/x-java-properties"); + connection.setRequestProperty("Content-Type", "text/x-java-properties"); + // connection.setUseCaches(false); + // + // Adding this in. It seems the HttpUrlConnection class does NOT + // properly forward our headers for POST re-direction. It does so + // for a GET re-direction. + // + // So we need to handle this ourselves. + // + //TODO - is this needed for a PUT? seems better to leave in for now? +// connection.setInstanceFollowRedirects(false); + // + // PLD - MUST be able to handle re-directs. + // + connection.setInstanceFollowRedirects(true); + connection.setDoOutput(true); + // connection.setDoInput(true); + try (OutputStream os = connection.getOutputStream()) { + + PDPGroup group = papEngine.getPDPGroup(pdp); + // if the PDP was just deleted, there is no group, but we want to send an update anyway + if (group == null) { + // create blank properties files + Properties policyProperties = new Properties(); + policyProperties.put(XACMLProperties.PROP_ROOTPOLICIES, ""); + policyProperties.put(XACMLProperties.PROP_REFERENCEDPOLICIES, ""); + policyProperties.store(os, ""); + + Properties pipProps = new Properties(); + pipProps.setProperty(XACMLProperties.PROP_PIP_ENGINES, ""); + pipProps.store(os, ""); + + } else { + // send properties from the current group + group.getPolicyProperties().store(os, ""); + Properties policyLocations = new Properties(); + for (PDPPolicy policy : group.getPolicies()) { + policyLocations.put(policy.getId() + ".url", XACMLPapServlet.papURL + "?id=" + policy.getId()); + } + policyLocations.store(os, ""); + group.getPipConfigProperties().store(os, ""); + } + + } catch (Exception e) { + logger.error("Failed to send property file to " + pdp.getId(), e); + // Since this is a server-side error, it probably does not reflect a problem on the client, + // so do not change the PDP status. + return; + } + // + // Do the connect + // + connection.connect(); + if (connection.getResponseCode() == 204) { + logger.info("Success. We are configured correctly."); + setPDPSummaryStatus(pdp, PDPStatus.Status.UP_TO_DATE); + } else if (connection.getResponseCode() == 200) { + logger.info("Success. PDP needs to update its configuration."); + setPDPSummaryStatus(pdp, PDPStatus.Status.OUT_OF_SYNCH); + } else { + logger.warn("Failed: " + connection.getResponseCode() + " message: " + connection.getResponseMessage()); + setPDPSummaryStatus(pdp, PDPStatus.Status.UNKNOWN); + } + } catch (Exception e) { + logger.error("Unable to sync config with PDP '" + pdp.getId() + "': " + e, e); + try { + setPDPSummaryStatus(pdp, PDPStatus.Status.UNKNOWN); + } catch (PAPException e1) { + logger.error("Unable to set status of PDP '" + pdp.getId() + "' to UNKNOWN: " + e, e); + } + } finally { + // cleanup the connection + connection.disconnect(); + + // tell the AC to update it's status info + notifyAC(); + } + + } + } + + // + // RESTful Interface from PAP to ACs notifying them of changes + // + + private void notifyAC() { + // kick off a thread to do one event notification for all registered ACs + // This needs to be on a separate thread so that ACs can make calls back to PAP to get the updated Group data + // as part of processing this message on their end. + Thread t = new Thread(new NotifyACThread()); + t.start(); + } + + private class NotifyACThread implements Runnable { + + public void run() { + List<String> disconnectedACs = new ArrayList<String>(); +// logger.debug("LIST SIZE="+adminConsoleURLStringList.size()); + + // There should be no Concurrent exception here because the list is a CopyOnWriteArrayList. + // The "for each" loop uses the collection's iterator under the covers, so it should be correct. + for (String acURL : adminConsoleURLStringList) { + HttpURLConnection connection = null; + try { + + acURL += "?PAPNotification=true"; + +//TODO - Currently we just tell AC that "Something changed" without being specific. Do we want to tell it which group/pdp changed? +//TODO - If so, put correct parameters into the Query string here + acURL += "&objectType=all" + "&action=update"; + + if (logger.isDebugEnabled()) { + logger.debug("creating url for id '" + acURL + "'"); + } +//TODO - currently always send both policies and pips. Do we care enough to add code to allow sending just one or the other? +//TODO (need to change "cache=", implying getting some input saying which to change) + + URL url = new URL(acURL ); + + // + // Open up the connection + // + connection = (HttpURLConnection)url.openConnection(); + // + // Setup our method and headers + // + connection.setRequestMethod("PUT"); + connection.setRequestProperty("Content-Type", "text/x-java-properties"); + // + // Adding this in. It seems the HttpUrlConnection class does NOT + // properly forward our headers for POST re-direction. It does so + // for a GET re-direction. + // + // So we need to handle this ourselves. + // + //TODO - is this needed for a PUT? seems better to leave in for now? + connection.setInstanceFollowRedirects(false); + // + // Do not include any data in the PUT because this is just a + // notification to the AC. + // The AC will use GETs back to the PAP to get what it needs + // to fill in the screens. + // + + // + // Do the connect + // + connection.connect(); + if (connection.getResponseCode() == 204) { + logger.info("Success. We updated correctly."); + } else { + logger.warn("Failed: " + connection.getResponseCode() + " message: " + connection.getResponseMessage()); + } + + } catch (Exception e) { + logger.error("Unable to sync config AC '" + acURL + "': " + e, e); + disconnectedACs.add(acURL); + } finally { + // cleanup the connection + connection.disconnect(); + } + } + + // remove any ACs that are no longer connected + if (disconnectedACs.size() > 0) { + adminConsoleURLStringList.removeAll(disconnectedACs); + } + + } + } + +}
http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/src/main/resources/log4j.properties ---------------------------------------------------------------------- diff --git a/openaz-xacml-pap-rest/src/main/resources/log4j.properties b/openaz-xacml-pap-rest/src/main/resources/log4j.properties new file mode 100755 index 0000000..b45fa2f --- /dev/null +++ b/openaz-xacml-pap-rest/src/main/resources/log4j.properties @@ -0,0 +1,22 @@ +# +# Use this properties for debugging and development. +# +# +# Set root logger level to DEBUG and its only appender to A1. +log4j.rootLogger=DEBUG, MAIN_LOG + +# A1 is set to be a ConsoleAppender. +log4j.appender.MAIN_LOG=org.apache.log4j.ConsoleAppender + +# A1 uses PatternLayout. +log4j.appender.MAIN_LOG.layout=org.apache.log4j.PatternLayout +log4j.appender.MAIN_LOG.layout.ConversionPattern=%d{yyyy_MM_dd_HH_mm_ss_SSS} [%t] %-5p %l- %m%n + +# +# This is specifically for Xacml request/response logging +# +log4j.logger.xacml.request=INFO, REQUEST_LOG + +log4j.appender.REQUEST_LOG=org.apache.log4j.ConsoleAppender +log4j.appender.REQUEST_LOG.layout=org.apache.log4j.PatternLayout +log4j.appender.REQUEST_LOG.layout.ConversionPattern=%d{yyyy_MM_dd_HH_mm_ss_SSS} %m%n \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$1.class ---------------------------------------------------------------------- diff --git a/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$1.class b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$1.class new file mode 100644 index 0000000..352e4c6 Binary files /dev/null and b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$1.class differ http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$Heartbeat.class ---------------------------------------------------------------------- diff --git a/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$Heartbeat.class b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$Heartbeat.class new file mode 100644 index 0000000..aac4b91 Binary files /dev/null and b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$Heartbeat.class differ http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$NotifyACThread.class ---------------------------------------------------------------------- diff --git a/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$NotifyACThread.class b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$NotifyACThread.class new file mode 100644 index 0000000..3d756fd Binary files /dev/null and b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$NotifyACThread.class differ http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$UpdatePDPThread.class ---------------------------------------------------------------------- diff --git a/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$UpdatePDPThread.class b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$UpdatePDPThread.class new file mode 100644 index 0000000..ffd1592 Binary files /dev/null and b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet$UpdatePDPThread.class differ http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet.class ---------------------------------------------------------------------- diff --git a/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet.class b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet.class new file mode 100644 index 0000000..d8d63b5 Binary files /dev/null and b/openaz-xacml-pap-rest/target/classes/com/att/research/xacml/rest/XACMLPapServlet.class differ http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/classes/log4j.properties ---------------------------------------------------------------------- diff --git a/openaz-xacml-pap-rest/target/classes/log4j.properties b/openaz-xacml-pap-rest/target/classes/log4j.properties new file mode 100644 index 0000000..b45fa2f --- /dev/null +++ b/openaz-xacml-pap-rest/target/classes/log4j.properties @@ -0,0 +1,22 @@ +# +# Use this properties for debugging and development. +# +# +# Set root logger level to DEBUG and its only appender to A1. +log4j.rootLogger=DEBUG, MAIN_LOG + +# A1 is set to be a ConsoleAppender. +log4j.appender.MAIN_LOG=org.apache.log4j.ConsoleAppender + +# A1 uses PatternLayout. +log4j.appender.MAIN_LOG.layout=org.apache.log4j.PatternLayout +log4j.appender.MAIN_LOG.layout.ConversionPattern=%d{yyyy_MM_dd_HH_mm_ss_SSS} [%t] %-5p %l- %m%n + +# +# This is specifically for Xacml request/response logging +# +log4j.logger.xacml.request=INFO, REQUEST_LOG + +log4j.appender.REQUEST_LOG=org.apache.log4j.ConsoleAppender +log4j.appender.REQUEST_LOG.layout=org.apache.log4j.PatternLayout +log4j.appender.REQUEST_LOG.layout.ConversionPattern=%d{yyyy_MM_dd_HH_mm_ss_SSS} %m%n \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/maven-archiver/pom.properties ---------------------------------------------------------------------- diff --git a/openaz-xacml-pap-rest/target/maven-archiver/pom.properties b/openaz-xacml-pap-rest/target/maven-archiver/pom.properties new file mode 100644 index 0000000..022f696 --- /dev/null +++ b/openaz-xacml-pap-rest/target/maven-archiver/pom.properties @@ -0,0 +1,5 @@ +#Generated by Maven +#Tue Apr 07 07:42:37 EDT 2015 +version=0.0.1-SNAPSHOT +groupId=org.openliberty.openaz +artifactId=openaz-xacml-pap-rest http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst ---------------------------------------------------------------------- diff --git a/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 0000000..4cfb3ef --- /dev/null +++ b/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst @@ -0,0 +1,5 @@ +com/att/research/xacml/rest/XACMLPapServlet$Heartbeat.class +com/att/research/xacml/rest/XACMLPapServlet$1.class +com/att/research/xacml/rest/XACMLPapServlet.class +com/att/research/xacml/rest/XACMLPapServlet$UpdatePDPThread.class +com/att/research/xacml/rest/XACMLPapServlet$NotifyACThread.class http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst ---------------------------------------------------------------------- diff --git a/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 0000000..9a51391 --- /dev/null +++ b/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1 @@ +/Users/ajith/IdeaProjects/openaz/openaz-xacml-pap-rest/src/main/java/com/att/research/xacml/rest/XACMLPapServlet.java http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst ---------------------------------------------------------------------- diff --git a/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst b/openaz-xacml-pap-rest/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst new file mode 100644 index 0000000..e69de29 http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/target/openaz-xacml-pap-rest-0.0.1-SNAPSHOT.jar ---------------------------------------------------------------------- diff --git a/openaz-xacml-pap-rest/target/openaz-xacml-pap-rest-0.0.1-SNAPSHOT.jar b/openaz-xacml-pap-rest/target/openaz-xacml-pap-rest-0.0.1-SNAPSHOT.jar new file mode 100644 index 0000000..d8cdce7 Binary files /dev/null and b/openaz-xacml-pap-rest/target/openaz-xacml-pap-rest-0.0.1-SNAPSHOT.jar differ http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pap-rest/xacml.pap.properties ---------------------------------------------------------------------- diff --git a/openaz-xacml-pap-rest/xacml.pap.properties b/openaz-xacml-pap-rest/xacml.pap.properties new file mode 100755 index 0000000..05fc0c5 --- /dev/null +++ b/openaz-xacml-pap-rest/xacml.pap.properties @@ -0,0 +1,35 @@ +# +# This is our factory that will create our engine +# +xacml.PAP.papEngineFactory=com.att.research.xacml.std.pap.StdEngineFactory + +# +# Where we store our PAP PDP Group/Node information +# +xacml.pap.pdps=pdps +# +# Need the PAP's url (how PDPs will reach it) configured here +# because we need it to generate the URLs of the Policy Files +# sent to the PDPs in the configuration when the PAP is first brought up. +# (In other cases, such as the PDP calling the PAP, we could generate this URL, +# but for startup there is no other way to get it.) +# +# +xacml.rest.pap.url=http://localhost:9090/pap/ + +# +# Upon startup, have the PAP servlet send latest configuration information to all +# the PDP nodes it knows about. +# +xacml.rest.pap.initiate.pdp=true +# +# Heartbeat from PAP to PDPs +# +# How much time (in milliseconds) between heartbeats +# (i.e. the time between completing the heartbeat with all PDPs and starting the next cycle) +# +xacml.rest.pap.heartbeat.interval=10000 +# +# Heartbeat connection timeout (in milliseconds) +# +xacml.rest.pap.heartbeat.timeout=10000 \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pdp-rest/WebContent/META-INF/MANIFEST.MF ---------------------------------------------------------------------- diff --git a/openaz-xacml-pdp-rest/WebContent/META-INF/MANIFEST.MF b/openaz-xacml-pdp-rest/WebContent/META-INF/MANIFEST.MF new file mode 100755 index 0000000..58630c0 --- /dev/null +++ b/openaz-xacml-pdp-rest/WebContent/META-INF/MANIFEST.MF @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 + http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pdp-rest/WebContent/WEB-INF/lib/sqljdbc4.jar ---------------------------------------------------------------------- diff --git a/openaz-xacml-pdp-rest/WebContent/WEB-INF/lib/sqljdbc4.jar b/openaz-xacml-pdp-rest/WebContent/WEB-INF/lib/sqljdbc4.jar new file mode 100755 index 0000000..d6b7f6d Binary files /dev/null and b/openaz-xacml-pdp-rest/WebContent/WEB-INF/lib/sqljdbc4.jar differ http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pdp-rest/config/xacml.pip.properties ---------------------------------------------------------------------- diff --git a/openaz-xacml-pdp-rest/config/xacml.pip.properties b/openaz-xacml-pdp-rest/config/xacml.pip.properties new file mode 100755 index 0000000..0c16eb3 --- /dev/null +++ b/openaz-xacml-pdp-rest/config/xacml.pip.properties @@ -0,0 +1,219 @@ +# PIP Engine Definition +# +xacml.pip.engines=csv1,csv2,hyper1,sql1,ldap1 + +csv1.classname=com.att.research.xacml.std.pip.engines.csv.CSVEngine +csv1.name=Master +csv1.description=Sean Lahman Basebase stats - Player names, DOB, and biographical info +csv1.issuer=com:att:research:xacml:test:csv +csv1.source=../XACML-TEST/testsets/pip/configurable-csv/adminDB/Master.txt +csv1.maxsize=4000000 +csv1.delimiter=, +csv1.quote=" +csv1.skip=0 + +csv1.resolvers=data + +csv1.resolver.data.classname=com.att.research.xacml.std.pip.engines.csv.ConfigurableCSVResolver +csv1.resolver.data.name=Player Resolver +csv1.resolver.data.description=This resolver finds player information in the Master table. +csv1.resolver.data.fields=firstname,lastname,deathyear,deathmonth,deathday,debut,finalgame +csv1.resolver.data.field.firstname.column=16 +csv1.resolver.data.field.firstname.id=com:att:research:xacml:test:csv:subject:firstname +csv1.resolver.data.field.firstname.datatype=http://www.w3.org/2001/XMLSchema#string +csv1.resolver.data.field.firstname.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject + +csv1.resolver.data.field.lastname.column=17 +csv1.resolver.data.field.lastname.id=com:att:research:xacml:test:csv:subject:lastname +csv1.resolver.data.field.lastname.datatype=http://www.w3.org/2001/XMLSchema#string +csv1.resolver.data.field.lastname.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject + +csv1.resolver.data.field.deathyear.column=10 +csv1.resolver.data.field.deathyear.id=com:att:research:xacml:test:csv:subject:deathyear +csv1.resolver.data.field.deathyear.datatype=http://www.w3.org/2001/XMLSchema#integer +csv1.resolver.data.field.deathyear.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject + +csv1.resolver.data.field.deathmonth.column=11 +csv1.resolver.data.field.deathmonth.id=com:att:research:xacml:test:csv:subject:deathmonth +csv1.resolver.data.field.deathmonth.datatype=http://www.w3.org/2001/XMLSchema#integer +csv1.resolver.data.field.deathmonth.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject + +csv1.resolver.data.field.deathday.column=12 +csv1.resolver.data.field.deathday.id=com:att:research:xacml:test:csv:subject:deathday +csv1.resolver.data.field.deathday.datatype=http://www.w3.org/2001/XMLSchema#integer +csv1.resolver.data.field.deathday.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject + +csv1.resolver.data.field.debut.column=25 +csv1.resolver.data.field.debut.id=com:att:research:xacml:test:csv:subject:debut +csv1.resolver.data.field.debut.datatype=http://www.w3.org/2001/XMLSchema#date +csv1.resolver.data.field.debut.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject + +csv1.resolver.data.field.finalgame.column=26 +csv1.resolver.data.field.finalgame.id=com:att:research:xacml:test:csv:subject:finalgame +csv1.resolver.data.field.finalgame.datatype=http://www.w3.org/2001/XMLSchema#date +csv1.resolver.data.field.finalgame.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject + +csv1.resolver.data.parameters=playerid +csv1.resolver.data.parameter.playerid.column=1 +csv1.resolver.data.parameter.playerid.id=urn:oasis:names:tc:xacml:1.0:subject:subject-id +csv1.resolver.data.parameter.playerid.datatype=http://www.w3.org/2001/XMLSchema#string +csv1.resolver.data.parameter.playerid.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject + +csv2.classname=com.att.research.xacml.std.pip.engines.csv.CSVEngine +csv2.name=Appearances +csv2.description=Sean Lahman Basebase stats - Player appearances for a team in a given year. +#csv2.issuer= +csv2.source=../XACML-TEST/testsets/pip/configurable-csv/adminDB/Appearances.txt +csv2.maxsize=4000000 +csv2.delimiter=, +csv2.quote=" +csv2.skip=0 + +csv2.resolvers=data + +csv2.resolver.data.classname=com.att.research.xacml.std.pip.engines.csv.ConfigurableCSVResolver +csv2.resolver.data.name=Appearance Resolver +csv2.resolver.data.description=This resolver returns all the appearances for a player from the appearance table. +csv2.resolver.data.fields=appearance +csv2.resolver.data.field.appearance.column=0 +csv2.resolver.data.field.appearance.id=com:att:research:xacml:test:csv:subject:appearance +csv2.resolver.data.field.appearance.datatype=http://www.w3.org/2001/XMLSchema#integer +csv2.resolver.data.field.appearance.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject +csv2.resolver.data.field.appearance.issuer=com:att:research:xacml:test:csv + +csv2.resolver.data.parameters=playerid +csv2.resolver.data.parameter.playerid.column=3 +csv2.resolver.data.parameter.playerid.id=urn:oasis:names:tc:xacml:1.0:subject:subject-id +csv2.resolver.data.parameter.playerid.datatype=http://www.w3.org/2001/XMLSchema#string +csv2.resolver.data.parameter.playerid.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject +#csv1.resolver.data.parameter.playerid.issuer= + +hyper1.classname=com.att.research.xacml.std.pip.engines.csv.HyperCSVEngine +hyper1.name=World Marriage Age Limits +hyper1.description=Minimum age for female/male marriages with or without their parental consent. +hyper1.source=../XACML-TEST/testsets/pip/configurable-csv-hyper/marriage.csv +hyper1.target=marriage +hyper1.definition=country VARCHAR(80) PRIMARY KEY, wofemale INT, womale INT, wfemale INT, wmale INT, year INT, source VARCHAR(20) + +hyper1.resolvers=age_consent + +hyper1.resolver.age_consent.classname=com.att.research.xacml.std.pip.engines.jdbc.ConfigurableJDBCResolver +hyper1.resolver.age_consent.name=Ages +hyper1.resolver.age_consent.description=This returns all the age's for consent or no consent for a country. +hyper1.resolver.age_consent.select=SELECT wofemale,womale,wfemale,wmale FROM marriage WHERE country=? +hyper1.resolver.age_consent.fields=wofemale,womale,wfemale,wmale + +hyper1.resolver.age_consent.field.wofemale.id=com:att:research:xacml:test:csv:country:no-consent:female +hyper1.resolver.age_consent.field.wofemale.datatype=http://www.w3.org/2001/XMLSchema#integer +hyper1.resolver.age_consent.field.wofemale.category=com:att:research:xacml:test:csv:category:country +hyper1.resolver.age_consent.field.wofemale.issuer=com:att:research:xacml:test:csv + +hyper1.resolver.age_consent.field.womale.id=com:att:research:xacml:test:csv:country:no-consent:male +hyper1.resolver.age_consent.field.womale.datatype=http://www.w3.org/2001/XMLSchema#integer +hyper1.resolver.age_consent.field.womale.category=com:att:research:xacml:test:csv:category:country +hyper1.resolver.age_consent.field.womale.issuer=com:att:research:xacml:test:csv + +hyper1.resolver.age_consent.field.wfemale.id=com:att:research:xacml:test:csv:country:consent:female +hyper1.resolver.age_consent.field.wfemale.datatype=http://www.w3.org/2001/XMLSchema#integer +hyper1.resolver.age_consent.field.wfemale.category=com:att:research:xacml:test:csv:category:country +hyper1.resolver.age_consent.field.wfemale.issuer=com:att:research:xacml:test:csv + +hyper1.resolver.age_consent.field.wmale.id=com:att:research:xacml:test:csv:country:consent:male +hyper1.resolver.age_consent.field.wmale.datatype=http://www.w3.org/2001/XMLSchema#integer +hyper1.resolver.age_consent.field.wmale.category=com:att:research:xacml:test:csv:category:country +hyper1.resolver.age_consent.field.wmale.issuer=com:att:research:xacml:test:csv + +hyper1.resolver.age_consent.parameters=country +hyper1.resolver.age_consent.parameter.country.id=com:att:research:xacml:test:csv:country:name +hyper1.resolver.age_consent.parameter.country.datatype=http://www.w3.org/2001/XMLSchema#string +hyper1.resolver.age_consent.parameter.country.category=com:att:research:xacml:test:csv:category:country +#hyper1.resolver.age_consent.parameter.country.issuer= + +sql1.classname=com.att.research.xacml.std.pip.engines.jdbc.JDBCEngine +sql1.name=World +sql1.description=World Database from MySQL website. Copyright Statistics Finland, http://www.stat.fi/worldinfigures. +# This will be the default issuer for the resolvers. NOTE: Issuer only used for attributes provided by the engine. +sql1.issuer=com:att:research:xacml:test:sql +# +# This is the configuration for JDBC. You will have to setup the database and run the data\world*.sql script to +# create the tables and load the data. +# +sql1.type=jdbc +sql1.jdbc.driver=org.postgresql.Driver +sql1.jdbc.url=jdbc:postgresql://localhost:5432/world +sql1.jdbc.conn.user=sa +sql1.jdbc.conn.password= +# +# This is the configuration for JNDI datasource. +# +#sql1.type=jndi +#sql1.datasource=jdbc/xacml + +sql1.resolvers=langer + +sql1.resolver.langer.classname=com.att.research.xacml.std.pip.engines.jdbc.ConfigurableJDBCResolver +sql1.resolver.langer.name=Language +sql1.resolver.langer.description=This returns the language for a city. +sql1.resolver.langer.select=SELECT language FROM city INNER JOIN countrylanguage ON city.countrycode = countrylanguage.countrycode WHERE name=? +sql1.resolver.langer.fields=language +sql1.resolver.langer.field.language.id=com:att:research:xacml:test:sql:resource:city:language +sql1.resolver.langer.field.language.datatype=http://www.w3.org/2001/XMLSchema#string +sql1.resolver.langer.field.language.category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource +#You can override the default issuer that is set in the JDBCEngine definition if you want. +#sql1.resolver.langer.field.language.issuer=com:att:research:xacml:test:sql +sql1.resolver.langer.parameters=name +sql1.resolver.langer.parameter.name.id=urn:oasis:names:tc:xacml:1.0:resource:resource-id +sql1.resolver.langer.parameter.name.datatype=http://www.w3.org/2001/XMLSchema#string +sql1.resolver.langer.parameter.name.category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource + + +ldap1.classname=com.att.research.xacml.std.pip.engines.ldap.LDAPEngine +ldap1.name=LDAP PIP +ldap1.description=The LDAP containing the seven seas sample LDIF data. +ldap1.issuer=com:att:research:xacml:test:ldap +ldap1.java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory +# +# NOTE: You will have to setup a local LDAP server and load the data\apache-ds-tutorial.ldif before +# this example will work. +# +ldap1.java.naming.provider.url=ldap://localhost:10389 +#ldap.java.naming.security.principal= +#ldap.java.naming.security.credentials= +ldap1.scope=subtree + +ldap1.resolvers=dn,ship + +ldap1.resolver.dn.classname=com.att.research.xacml.std.pip.engines.ldap.ConfigurableLDAPResolver +ldap1.resolver.dn.name=Domain Names +ldap1.resolver.dn.description=Find all the dn's for the subject id +ldap1.resolver.dn.base=o=sevenseas +ldap1.resolver.dn.base.parameters= +ldap1.resolver.dn.filter=(|(uid=${uid})(mail=${uid})) +ldap1.resolver.dn.filter.parameters=uid +ldap1.resolver.dn.filter.parameters.uid.id=urn:oasis:names:tc:xacml:1.0:subject:subject-id +ldap1.resolver.dn.filter.parameters.uid.datatype=http://www.w3.org/2001/XMLSchema#string +ldap1.resolver.dn.filter.parameters.uid.category=urn:oasis:names:tc:xacml:1.0:subject-category:access-subject +#ldap1.resolver.dn.filter.parameters.uid.issuer=com:att:research:xacml:test:ldap +ldap1.resolver.dn.filter.view=dn +ldap1.resolver.dn.filter.view.dn.id=com:att:research:xacml:test:ldap:subject:dn +ldap1.resolver.dn.filter.view.dn.datatype=http://www.w3.org/2001/XMLSchema#string +ldap1.resolver.dn.filter.view.dn.category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource +ldap1.resolver.dn.filter.view.dn.issuer=com:att:research:xacml:test:ldap + +ldap1.resolver.ship.classname=com.att.research.xacml.std.pip.engines.ldap.ConfigurableLDAPResolver +ldap1.resolver.ship.name=Ship Resolver +ldap1.resolver.ship.description=This resolves a subject's dn to a ship. +ldap1.resolver.ship.base=o=sevenseas +ldap1.resolver.ship.base.parameters= +ldap1.resolver.ship.filter=uniquemember=${dn} +ldap1.resolver.ship.filter.parameters=dn +ldap1.resolver.ship.filter.parameters.dn.id=com:att:research:xacml:test:ldap:subject:dn +ldap1.resolver.ship.filter.parameters.dn.datatype=http://www.w3.org/2001/XMLSchema#string +ldap1.resolver.ship.filter.parameters.dn.category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource +ldap1.resolver.ship.filter.parameters.dn.issuer=com:att:research:xacml:test:ldap +ldap1.resolver.ship.filter.view=cn +ldap1.resolver.ship.filter.view.cn.id=com:att:research:xacml:test:ldap:subject:ship +ldap1.resolver.ship.filter.view.cn.datatype=http://www.w3.org/2001/XMLSchema#string +ldap1.resolver.ship.filter.view.cn.category=urn:oasis:names:tc:xacml:3.0:attribute-category:resource +ldap1.resolver.ship.filter.view.cn.issuer=com:att:research:xacml:test:ldap + http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pdp-rest/config/xacml.policy.properties ---------------------------------------------------------------------- diff --git a/openaz-xacml-pdp-rest/config/xacml.policy.properties b/openaz-xacml-pdp-rest/config/xacml.policy.properties new file mode 100755 index 0000000..d42c84c --- /dev/null +++ b/openaz-xacml-pdp-rest/config/xacml.policy.properties @@ -0,0 +1,8 @@ +xacml.rootPolicies=annotation,ldap,csv,csvhyper,sql +xacml.referencedPolicies= + +annotation.file=../XACML-TEST/testsets/annotation/AnnotationPolicy.v1.xml +ldap.file=../XACML-TEST/testsets/pip/configurable-ldap/LDAP-Seven-Seas-v1.xml +csv.file=../XACML-TEST/testsets/pip/configurable-csv/CSV-Baseball-Hall-Of-Fame-v1.xml +csvhyper.file=../XACML-TEST/testsets/pip/configurable-csv-hyper/CSV-Legal-Age-Marriage-v1.xml +sql.file=../XACML-TEST/testsets/pip/configurable-sql/SQL-World-Languages-v1.xml http://git-wip-us.apache.org/repos/asf/incubator-openaz/blob/94fcdd90/openaz-xacml-pdp-rest/pom.xml ---------------------------------------------------------------------- diff --git a/openaz-xacml-pdp-rest/pom.xml b/openaz-xacml-pdp-rest/pom.xml new file mode 100755 index 0000000..edb97b4 --- /dev/null +++ b/openaz-xacml-pdp-rest/pom.xml @@ -0,0 +1,72 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>openaz</artifactId> + <groupId>org.openliberty.openaz</groupId> + <version>0.0.1-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + <artifactId>openaz-xacml-pdp-rest</artifactId> + + <dependencies> + <dependency> + <groupId>org.openliberty.openaz</groupId> + <artifactId>openaz-xacml</artifactId> + </dependency> + <dependency> + <groupId>org.openliberty.openaz</groupId> + <artifactId>openaz-xacml-rest</artifactId> + </dependency> + <dependency> + <groupId>org.openliberty.openaz</groupId> + <artifactId>openaz-xacml-pdp</artifactId> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> + </dependency> + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + </dependency> + <dependency> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + </dependency> + <dependency> + <groupId>com.google.guava</groupId> + <artifactId>guava</artifactId> + </dependency> + <dependency> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + </dependency> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + </dependency> + <dependency> + <groupId>mysql</groupId> + <artifactId>mysql-connector-java</artifactId> + </dependency> + <dependency> + <groupId>postgresql</groupId> + <artifactId>postgresql</artifactId> + </dependency> + <dependency> + <groupId>org.hsqldb</groupId> + <artifactId>hsqldb</artifactId> + </dependency> + </dependencies> + +</project> \ No newline at end of file
