router-authz.js revision bd040ebb8e96fb1d0bfd1a3445a649dd9c6f8120
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * Copyright (c) 2011-2012 ForgeRock AS. All rights reserved.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * The contents of this file are subject to the terms
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * of the Common Development and Distribution License
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * (the License). You may not use this file except in
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * compliance with the License.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * You can obtain a copy of the License at
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * See the License for the specific language governing
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * permission and limitations under the License.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * When distributing Covered Code, include this CDDL
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * Header Notice in each file and include the License file
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * If applicable, add the following below the CDDL Header,
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * with the fields enclosed by brackets [] replaced by
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * your own identifying information:
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * "Portions Copyrighted [year] [name of copyright owner]"
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * This script is called from the router "onRequest" trigger, to enforce a central
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * set of authorization rules.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * This default implemention simply restricts requests via HTTP to users that are assigned
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * an "openidm-admin" role, and optionally to those that authenticate with TLS mutual
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk * authentication (assigned an "openidm-cert" role).
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk var taskInstance = openidm.read("workflow/taskinstance/" + taskInstanceId);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return taskInstance.assignee === request.parent.security.username;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return isMyTask() || isUserCandidateForTask(taskInstanceId);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkfunction isUserCandidateForTask(taskInstanceId) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk "taskCandidateUser": request.parent.security.username
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk var userCandidateTasks = openidm.query("workflow/taskinstance", userCandidateTasksQueryParams).result;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk for (var i = 0; i < userCandidateTasks.length; i++) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (taskInstanceId === userCandidateTasks[i]._id) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return true;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk for (var i = 0; i < request.parent.security['openidm-roles'].length; i++) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk var role = request.parent.security['openidm-roles'][i];
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (i === 0) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk var userGroupCandidateTasks = openidm.query("workflow/taskinstance", userGroupCandidateTasksQueryParams).result;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk for (var i = 0; i < userGroupCandidateTasks.length; i++) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (taskInstanceId === userGroupCandidateTasks[i]._id) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return true;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return false;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk var processDefinitionId = request.value._processDefinitionId;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return isProcessOnUsersList(processDefinitionId);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk var processDefinitionId = request.id.split("/")[2];
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return isProcessOnUsersList(processDefinitionId);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkfunction isProcessOnUsersList(processDefinitionId) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk var processesForUser = openidm.query("endpoint/getprocessesforuser", processesForUserQueryParams);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk for (var i = 0; i < processesForUser.length; i++) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (processDefinitionId === processForUser._id) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk contains(allowedQueries[request.id], request.params["_queryId"])
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return false;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk var ui_config = openidm.read("config/ui/configuration");
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return (ui_config && ui_config.configuration && ui_config.configuration[param]);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk userId = request.id.match(/managed\/user\/(.*)/i);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk // something funny going on if we have two different values for userId
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (userId !== null && userId.length && userId !== request.params.userId) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return false;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk // something funny going on if we have two different values for userId
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (userId !== null && userId.length && userId !== request.params.userId) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return false;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return userId === request.parent.security.userid.id;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkfunction managedUserRestrictedToAllowedProperties(allowedPropertiesList) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk var i = 0,requestedRoles = [],params = {},currentUser = {};
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return true;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk else { // this would be strange, but worth checking
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return true; // true because they don't appear to be setting anything
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk // we could accept a csv list or an array of properties for the allowedPropertiesList arg.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (typeof allowedPropertiesList === "string") {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk allowedPropertiesList = allowedPropertiesList.split(',');
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (request.method === "patch" || (request.method === "action" && request.params["_action"] === "patch")) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk // check each of the fields they are attempting to patch and make sure they are approved
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if ((params[i].test && !containsIgnoreCase(allowedPropertiesList, params[i].test.replace(/^\//, ''))) ||
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk (params[i].add && !containsIgnoreCase(allowedPropertiesList, params[i].add.replace(/^\//, ''))) ||
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk (params[i].replace && !containsIgnoreCase(allowedPropertiesList, params[i].replace.replace(/^\//, '')))) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return false;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (!currentUser || currentUser._id !== request.parent.security.userid.id) { // this would be odd, but just in case
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return false;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk // if the new value does not match the current value, then they must be updating it
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk // if the field they are attempting to update isn't allowed for them, then reject request.
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (currentUser[i] !== params[i] && !containsIgnoreCase(allowedPropertiesList,i)) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return false;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk // they should only be providing parameters that they are allowed to define
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (!containsIgnoreCase(allowedPropertiesList,i)) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return false;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return true;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (request.params && typeof request.params['_queryExpression'] != "undefined") {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return false;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return true;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk//////// Do not alter functions below here as part of your authz configuration
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkfunction passesAccessConfig(id, roles, method, action) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk for (var i = 0; i < httpAccessConfig.configs.length; i++) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk // Check resource ID
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk // Check excludePatterns
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (typeof(config.excludePatterns) != 'undefined' && config.excludePatterns != null) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk var excluded = config.excludePatterns.split(',');
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk var ex = false;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (matchesResourceIdPattern(id, excluded[j])) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk // Check roles
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (containsItems(roles, config.roles.split(','))) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk // Check method
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (method == 'undefined' || containsItem(method, config.methods)) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk // Check action
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (action == 'undefined' || action == "" || containsItem(action, config.actions)) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (typeof(config.customAuthz) != 'undefined' && config.customAuthz != null) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return true;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return true;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return false;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk // Accept all patterns
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return true;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk // pattern matches exactly
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return true;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk } else if (pattern.indexOf("/*", pattern.length - 2) !== -1) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk // Ends with "/*" or "/"
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk // See if parent pattern matches
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk var parentResource = pattern.substring(0, pattern.length - 1);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (id.length >= parentResource.length && id.substring(0, parentResource.length) == parentResource) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return false;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return true;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (containsIgnoreCase(configItems, items[i])) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return true;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return false
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return true;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return containsIgnoreCase(configItems.split(','), item);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (typeof(a) != 'undefined' && a != null) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (typeof(o) != 'undefined' && o != null) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (typeof(a[i]) != 'undefined' && a[i] != null) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return true;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return false;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenkfunction contains(a, o) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (typeof(a) != 'undefined' && a != null) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (a[i] === o) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return true;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return false;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (request.parent == null || request.parent == undefined || request.parent.type != 'http') {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return true;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk var roles = request.parent.security['openidm-roles'];
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (request.params && request.params['_action']) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk // Check REST requests against the access configuration
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk logger.debug("Access Check for HTTP request for resource id: " + request.id);
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk if (passesAccessConfig(request.id, roles, request.method, action)) {
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk return true;
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk// Load the access configuration script
4b8d88eb610aa1e0bb6ec632f792744b3d6b5f22jeff.schenk// java.lang.System.out.println(request);