router-authz.js revision f8eb547a5996303c92e9482cf659642871c7252c
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Copyright (c) 2011-2012 ForgeRock AS. All rights reserved.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * The contents of this file are subject to the terms
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * of the Common Development and Distribution License
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * (the License). You may not use this file except in
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * compliance with the License.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * You can obtain a copy of the License at
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * See the License for the specific language governing
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * permission and limitations under the License.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * When distributing Covered Code, include this CDDL
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * Header Notice in each file and include the License file
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * If applicable, add the following below the CDDL Header,
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * with the fields enclosed by brackets [] replaced by
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * your own identifying information:
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * "Portions Copyrighted [year] [name of copyright owner]"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * This script is called from the router "onRequest" trigger, to enforce a central
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * set of authorization rules.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * This default implemention simply restricts requests via HTTP to users that are assigned
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * an "openidm-admin" role, and optionally to those that authenticate with TLS mutual
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * authentication (assigned an "openidm-cert" role).
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * A configuration for allowed requests. Each entry in the config contains a pattern to match
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * against the incoming request ID and, in the event of a match, the associated roles, methods,
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * and actions that are allowed for requests on that particular pattern.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * pattern: A pattern to match against an incoming request's resource ID
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * roles: A comma separated list of allowed roles
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * methods: A comma separated list of allowed methods
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * actions: A comma separated list of allowed actions
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * customAuthz: A custom function for additional authorization logic/checks (optional)
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * A single '*' character indicates all possible values. With patterns ending in "/*", the "*"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * acts as a wild card to indicate the pattern accepts all resource IDs "below" the specified
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * pattern (prefix). For example the pattern "managed/*" would match "managed/user" or anything
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * starting with "managed/". Note: it would not match "managed", which would need to have its
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk * own entry in the config.
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "configs" : [
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk // Anyone can read from these endpoints
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk // These options should only be available anonymously if selfReg is enabled
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "customAuthz" : "checkIfUIIsEnabled('selfRegistration')"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "customAuthz" : "checkIfUIIsEnabled('selfRegistration') && managedUserRestrictedToAllowedRoles('openidm-authorized')"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk // Anonymous user can call the siteIdentification endpoint if it is enabled:
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "customAuthz" : "checkIfUIIsEnabled('siteIdentification')"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk // Anonymous user can call the securityQA endpoint if it enabled:
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "customAuthz" : "checkIfUIIsEnabled('securityQuestions')"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk // This is needed by both self reg and security questions
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "customAuthz" : "checkIfUIIsEnabled('selfRegistration') || checkIfUIIsEnabled('securityQuestions')"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk // openidm-admin can request anything
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "methods" : "*", // default to all methods allowed
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "actions" : "*" // default to all actions allowed
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk // admin can request anything in managed/user
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "methods" : "*", // default to all methods allowed
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "actions" : "*" // default to all actions allowed
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "methods" : "*", // default to all methods allowed
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "actions" : "*" // default to all actions allowed
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk // Additional checks for authenticated users
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "roles" : "openidm-authorized", // openidm-authorized is logged-in users
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "methods" : "create,read,update,patch,action,query", // note the missing 'delete' - by default, users cannot delete things
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "customAuthz" : "ownDataOnly() && managedUserRestrictedToAllowedRoles('openidm-authorized')"
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk // enforcement of which notifications you can read and delete is done within the endpoint
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk // Workflow-related endpoints for authorized users
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk // Clients authenticated via SSL mutual authentication
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "methods" : "", // default to no methods allowed
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk var taskInstance = openidm.read("workflow/taskinstance/" + taskInstanceId);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return taskInstance.assignee === request.parent.security.username;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return isMyTask() || isUserCandidateForTask(taskInstanceId);
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenkfunction isUserCandidateForTask(taskInstanceId) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk "taskCandidateUser": request.parent.security.username
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk var userCandidateTasks = openidm.query("workflow/taskinstance", userCandidateTasksQueryParams).result;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk for (var i = 0; i < userCandidateTasks.length; i++) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (taskInstanceId === userCandidateTasks[i]._id) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk return true;
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk for (var i = 0; i < request.parent.security['openidm-roles'].length; i++) {
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk var role = request.parent.security['openidm-roles'][i];
c1350cf5bc50458ba79cc93ff9e0e5fe3f1aeeb0jeff.schenk if (i === 0) {
var userGroupCandidateTasks = openidm.query("workflow/taskinstance", userGroupCandidateTasksQueryParams).result;
function isAllowedToStartProcess() {
function isOneOfMyWorkflows() {
var processesForUserQueryParams = {
var isProcessOneOfUserProcesses = false;
isProcessOneOfUserProcesses = true;
return isProcessOneOfUserProcesses;
var returnVal = false;
function ownDataOnly() {
if (request.method === "patch" || (request.method === "action" && request.params["_action"] === "patch")) {
for (i in params) {
if (typeof params.roles !== "string" && typeof params["/roles"] !== "string") { // this would also be strange, but worth checking
for (i in requestedRoles) {
if (id.length >= parentResource.length && id.substring(0, parentResource.length) == parentResource) {
function contains(a, o) {
function allow() {
if (!allow()) {