001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2012-2015 ForgeRock AS. 015 */ 016 017package org.forgerock.services.context; 018 019import static org.forgerock.util.Reject.checkNotNull; 020 021import java.util.Collections; 022import java.util.LinkedHashMap; 023import java.util.Map; 024 025import org.forgerock.json.JsonValue; 026 027/** 028 * A {@link Context} containing information about the client performing the 029 * request which may be used when performing authorization decisions. A security 030 * context will typically be created for each REST request and comprises of two 031 * fields: 032 * <ul> 033 * <li>an {@link #getAuthenticationId authentication ID} which is the principal 034 * that the client used during authentication. This might be a user name, an 035 * email address, etc. The authentication ID may be used for logging or auditing 036 * but SHOULD NOT be used when performing authorization decisions. 037 * <li>an {@link #getAuthorization authorization ID} which is a map containing 038 * additional principals associated with the client and which MAY be used when 039 * performing authorization decisions. Examples of principals include a unique 040 * identifier for the user, roles, or an LDAP distinguished name (DN). 041 * </ul> 042 * The following code illustrates how an application may obtain the realm 043 * associated with a user: 044 * 045 * <pre> 046 * Context context = ...; 047 * String realm = (String) context.asContext(SecurityContext.class).getAuthorization(AUTHZID_REALM); 048 * </pre> 049 * 050 * <pre> 051 * { 052 * "id" : "56f0fb7e-3837-464d-b9ec-9d3b6af665c3", 053 * "class" : "org.forgerock.services.context.SecurityContext", 054 * "parent" : { 055 * ... 056 * }, 057 * "authenticationId" : "bjensen@example.com", 058 * "authorization" : { 059 * "id" : "1230fb7e-f83b-464d-19ef-789b6af66456", 060 * "component" : "users", 061 * "roles" : [ 062 * "administrators" 063 * ], 064 * "dn" : "cn=bjensen,ou=people,dc=example,dc=com" 065 * } 066 * } 067 * </pre> 068 */ 069public final class SecurityContext extends AbstractContext { 070 071 /** 072 * The authorization ID name reserved for the name of the component in which 073 * a user's resource is located, e.g. "users". 074 */ 075 public static final String AUTHZID_COMPONENT = "component"; 076 077 /** 078 * The authorization ID name reserved for the user's LDAP distinguished 079 * name. 080 */ 081 public static final String AUTHZID_DN = "dn"; 082 083 /** 084 * The authorization ID principal name reserved for a user's unique 085 * identifier. 086 */ 087 public static final String AUTHZID_ID = "id"; 088 089 /** 090 * The authorization ID name reserved for a user's realm. 091 */ 092 public static final String AUTHZID_REALM = "realm"; 093 094 /** 095 * The authorization ID name reserved for the array of roles associated with 096 * the user. 097 */ 098 public static final String AUTHZID_ROLES = "roles"; 099 100 // Persisted attribute names 101 private static final String ATTR_AUTHENTICATION_ID = "authenticationId"; 102 private static final String ATTR_AUTHORIZATION = "authorization"; 103 104 /** 105 * Creates a new security context having the provided parent and an ID 106 * automatically generated using {@code UUID.randomUUID()}. 107 * 108 * @param parent 109 * The parent context. 110 * @param authenticationId 111 * The authentication ID that the user provided during 112 * authentication, which may be {@code null} or empty indicating 113 * that the client is unauthenticated. 114 * @param authorization 115 * The authorization information which should be used for 116 * authorizing requests may by the user, which may be 117 * {@code null} or empty indicating that the client is is to be 118 * treated as an anonymous user when performing authorization 119 * decisions. The provided map will be copied defensively and 120 * must only contain values which can be serialized as JSON 121 * values. 122 */ 123 public SecurityContext(final Context parent, 124 final String authenticationId, final Map<String, Object> authorization) { 125 this(null, parent, authenticationId, authorization); // no id 126 } 127 128 /** 129 * Creates a new security context having the provided ID, and parent. 130 * 131 * @param id 132 * The context ID. 133 * @param parent 134 * The parent context. 135 * @param authenticationId 136 * The authentication ID that the user provided during 137 * authentication, which may be {@code null} or empty indicating 138 * that the client is unauthenticated. 139 * @param authorization 140 * The authorization information which should be used for 141 * authorizing requests may by the user, which may be 142 * {@code null} or empty indicating that the client is is to be 143 * treated as an anonymous user when performing authorization 144 * decisions. The provided map will be copied defensively and 145 * must only contain values which can be serialized as JSON 146 * values. 147 */ 148 public SecurityContext(final String id, final Context parent, 149 final String authenticationId, final Map<String, Object> authorization) { 150 super(id, "security", checkNotNull(parent, "Cannot instantiate SecurityContext with null parent Context")); 151 data.put(ATTR_AUTHENTICATION_ID, authenticationId != null ? authenticationId : ""); 152 data.put(ATTR_AUTHORIZATION, authorization != null 153 ? Collections.unmodifiableMap(new LinkedHashMap<>(authorization)) 154 : Collections.<String, Object>emptyMap()); 155 } 156 157 /** 158 * Restore from JSON representation. 159 * 160 * @param savedContext 161 * The JSON representation from which this context's attributes 162 * should be parsed. 163 * @param classLoader 164 * The ClassLoader which can properly resolve the persisted class-name. 165 */ 166 public SecurityContext(final JsonValue savedContext, final ClassLoader classLoader) { 167 super(savedContext, classLoader); 168 } 169 170 /** 171 * Returns the principal that the client used during authentication. This 172 * might be a user name, an email address, etc. The authentication ID may be 173 * used for logging or auditing but SHOULD NOT be used for authorization 174 * decisions. 175 * 176 * @return The principal that the client used during authentication, which 177 * may be empty (but never {@code null}) indicating that the client 178 * is unauthenticated. 179 */ 180 public String getAuthenticationId() { 181 return data.get(ATTR_AUTHENTICATION_ID).asString(); 182 } 183 184 /** 185 * Returns an unmodifiable map containing additional principals associated 186 * with the client which MAY be used when performing authorization 187 * decisions. Examples of principals include a unique identifier for the 188 * user, roles, or an LDAP distinguished name (DN). The following code 189 * illustrates how an application may obtain the realm associated with a 190 * user: 191 * 192 * <pre> 193 * Context context = ...; 194 * String realm = (String) context.asContext(SecurityContext.class).getAuthorization(AUTHZID_REALM); 195 * </pre> 196 * 197 * @return An unmodifiable map containing additional principals associated 198 * with the client which MAY be used when performing authorization 199 * decisions. The returned map may be empty (but never {@code null}) 200 * indicating that the client is is to be treated as an anonymous 201 * user. 202 */ 203 public Map<String, Object> getAuthorization() { 204 return data.get(ATTR_AUTHORIZATION).asMap(); 205 } 206}