001/* 002 * oauth2-oidc-sdk 003 * 004 * Copyright 2012-2016, Connect2id Ltd and contributors. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.oauth2.sdk.id; 019 020 021import java.io.Serializable; 022import java.util.Objects; 023 024import com.nimbusds.oauth2.sdk.ParseException; 025import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; 026import net.jcip.annotations.Immutable; 027import net.minidev.json.JSONAware; 028import net.minidev.json.JSONObject; 029 030 031/** 032 * Authorised actor in impersonation and delegation cases. 033 */ 034@Immutable 035public final class Actor implements Serializable, Comparable<Actor>, JSONAware { 036 037 038 private static final long serialVersionUID = 4171395610729169757L; 039 040 041 /** 042 * The actor subject. 043 */ 044 private final Subject subject; 045 046 047 /** 048 * Optional issuer for the actor subject. 049 */ 050 private final Issuer issuer; 051 052 053 /** 054 * Optional parent for the actor. 055 */ 056 private final Actor parent; 057 058 059 /** 060 * Creates a new actor. 061 * 062 * @param subject The subject. Must not be {@code null}. 063 */ 064 public Actor(final Subject subject) { 065 this(subject, null, null); 066 } 067 068 069 /** 070 * Creates a new actor. 071 * 072 * @param subject The subject. Must not be {@code null}. 073 * @param issuer Optional issuer for the subject, {@code null} if 074 * not specified. 075 * @param parent Optional parent for the actor, {@code null} if none. 076 */ 077 public Actor(final Subject subject, final Issuer issuer, final Actor parent) { 078 if (subject == null) { 079 throw new IllegalArgumentException("The subject must not be null"); 080 } 081 this.subject = subject; 082 this.issuer = issuer; 083 this.parent = parent; 084 } 085 086 087 /** 088 * Returns the subject. 089 * 090 * @return The subject. 091 */ 092 public Subject getSubject() { 093 return subject; 094 } 095 096 097 /** 098 * Returns the optional issuer for the subject. 099 * 100 * @return The issuer, {@code null} if not specified. 101 */ 102 public Issuer getIssuer() { 103 return issuer; 104 } 105 106 107 /** 108 * Returns the optional parent for this actor. 109 * 110 * @return The optional parent for the actor, {@code null} if none. 111 */ 112 public Actor getParent() { 113 return parent; 114 } 115 116 117 /** 118 * Returns a JSON object representation of this actor. 119 * 120 * <p>Simple example: 121 * 122 * <pre> 123 * { 124 * "sub" : "[email protected]" 125 * } 126 * </pre> 127 * 128 * <p>With nesting: 129 * 130 * <pre> 131 * { 132 * "sub" : "consumer.example.com-web-application", 133 * "iss" : "https://issuer.example.net", 134 * "act" : { "sub":"[email protected]" } 135 * } 136 * </pre> 137 * 138 * @return The JSON object. 139 */ 140 public JSONObject toJSONObject() { 141 142 JSONObject o = new JSONObject(); 143 o.put("sub", subject.getValue()); 144 145 if (issuer != null) { 146 o.put("iss", issuer.getValue()); 147 } 148 149 if (parent != null) { 150 o.put("act", parent.toJSONObject()); 151 } 152 153 return o; 154 } 155 156 157 @Override 158 public int compareTo(final Actor other) { 159 160 return toJSONString().compareTo(other.toJSONString()); 161 } 162 163 164 @Override 165 public String toJSONString() { 166 return toJSONObject().toJSONString(); 167 } 168 169 170 @Override 171 public String toString() { 172 return toJSONString(); 173 } 174 175 176 @Override 177 public boolean equals(Object o) { 178 if (this == o) return true; 179 if (!(o instanceof Actor)) return false; 180 Actor actor = (Actor) o; 181 return getSubject().equals(actor.getSubject()) && Objects.equals(getIssuer(), actor.getIssuer()) && Objects.equals(getParent(), actor.getParent()); 182 } 183 184 185 @Override 186 public int hashCode() { 187 return Objects.hash(getSubject(), getIssuer(), getParent()); 188 } 189 190 191 /** 192 * Parses an actor from the specified JSON object representation. 193 * 194 * <p>Simple example: 195 * 196 * <pre> 197 * { 198 * "sub" : "[email protected]" 199 * } 200 * </pre> 201 * 202 * <p>With nesting: 203 * 204 * <pre> 205 * { 206 * "sub" : "consumer.example.com-web-application", 207 * "iss" : "https://issuer.example.net", 208 * "act" : { "sub":"[email protected]" } 209 * } 210 * </pre> 211 * 212 * @param jsonObject The JSON object. Must not be {@code null}. 213 * 214 * @return The actor. 215 * 216 * @throws ParseException If parsing failed. 217 */ 218 public static Actor parse(final JSONObject jsonObject) 219 throws ParseException { 220 221 Subject sub = new Subject(JSONObjectUtils.getString(jsonObject, "sub")); 222 223 Issuer iss = null; 224 225 if (jsonObject.containsKey("iss")) { 226 iss = new Issuer(JSONObjectUtils.getString(jsonObject, "iss")); 227 } 228 229 Actor parent = parseTopLevel(jsonObject); 230 231 return new Actor(sub, iss, parent); 232 } 233 234 235 /** 236 * Parses an actor from the specified top-level JSON object contains 237 * an optional actor JSON representation. 238 * 239 * <p>Simple example: 240 * 241 * <pre> 242 * { 243 * "aud" : "https://consumer.example.com", 244 * "iss" : "https://issuer.example.com", 245 * "exp" : 1443904177, 246 * "nbf" : 1443904077, 247 * "sub" : "[email protected]", 248 * "act" : { "sub" : "[email protected]" } 249 * } 250 * </pre> 251 * 252 * <p>With nesting: 253 * 254 * <pre> 255 * { 256 * "aud" : "https://backend.example.com", 257 * "iss" : "https://issuer.example.com", 258 * "exp" : 1443904100, 259 * "nbf" : 1443904000, 260 * "sub" : "[email protected]", 261 * "act" : { "sub" : "consumer.example.com-web-application", 262 * "iss" : "https://issuer.example.net", 263 * "act" : { "sub":"[email protected]" } } 264 * } 265 * </pre> 266 * 267 * @param jsonObject The top-level JSON object to parse. Must not be 268 * {@code null}. 269 * 270 * @return The actor, {@code null} if not specified. 271 * 272 * @throws ParseException If parsing failed. 273 */ 274 public static Actor parseTopLevel(final JSONObject jsonObject) 275 throws ParseException { 276 277 JSONObject actSpec = JSONObjectUtils.getJSONObject(jsonObject, "act", null); 278 279 if (actSpec == null) return null; 280 281 return parse(actSpec); 282 } 283}