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 com.nimbusds.oauth2.sdk.ParseException; 022import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; 023import net.jcip.annotations.Immutable; 024import net.minidev.json.JSONAware; 025import net.minidev.json.JSONObject; 026 027import java.io.Serializable; 028import java.util.Objects; 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 this.subject = Objects.requireNonNull(subject); 079 this.issuer = issuer; 080 this.parent = parent; 081 } 082 083 084 /** 085 * Returns the subject. 086 * 087 * @return The subject. 088 */ 089 public Subject getSubject() { 090 return subject; 091 } 092 093 094 /** 095 * Returns the optional issuer for the subject. 096 * 097 * @return The issuer, {@code null} if not specified. 098 */ 099 public Issuer getIssuer() { 100 return issuer; 101 } 102 103 104 /** 105 * Returns the optional parent for this actor. 106 * 107 * @return The optional parent for the actor, {@code null} if none. 108 */ 109 public Actor getParent() { 110 return parent; 111 } 112 113 114 /** 115 * Returns a JSON object representation of this actor. 116 * 117 * <p>Simple example: 118 * 119 * <pre> 120 * { 121 * "sub" : "[email protected]" 122 * } 123 * </pre> 124 * 125 * <p>With nesting: 126 * 127 * <pre> 128 * { 129 * "sub" : "consumer.example.com-web-application", 130 * "iss" : "https://issuer.example.net", 131 * "act" : { "sub":"[email protected]" } 132 * } 133 * </pre> 134 * 135 * @return The JSON object. 136 */ 137 public JSONObject toJSONObject() { 138 139 JSONObject o = new JSONObject(); 140 o.put("sub", subject.getValue()); 141 142 if (issuer != null) { 143 o.put("iss", issuer.getValue()); 144 } 145 146 if (parent != null) { 147 o.put("act", parent.toJSONObject()); 148 } 149 150 return o; 151 } 152 153 154 @Override 155 public int compareTo(final Actor other) { 156 157 return toJSONString().compareTo(other.toJSONString()); 158 } 159 160 161 @Override 162 public String toJSONString() { 163 return toJSONObject().toJSONString(); 164 } 165 166 167 @Override 168 public String toString() { 169 return toJSONString(); 170 } 171 172 173 @Override 174 public boolean equals(Object o) { 175 if (this == o) return true; 176 if (!(o instanceof Actor)) return false; 177 Actor actor = (Actor) o; 178 return getSubject().equals(actor.getSubject()) && Objects.equals(getIssuer(), actor.getIssuer()) && Objects.equals(getParent(), actor.getParent()); 179 } 180 181 182 @Override 183 public int hashCode() { 184 return Objects.hash(getSubject(), getIssuer(), getParent()); 185 } 186 187 188 /** 189 * Parses an actor from the specified JSON object representation. 190 * 191 * <p>Simple example: 192 * 193 * <pre> 194 * { 195 * "sub" : "[email protected]" 196 * } 197 * </pre> 198 * 199 * <p>With nesting: 200 * 201 * <pre> 202 * { 203 * "sub" : "consumer.example.com-web-application", 204 * "iss" : "https://issuer.example.net", 205 * "act" : { "sub":"[email protected]" } 206 * } 207 * </pre> 208 * 209 * @param jsonObject The JSON object. Must not be {@code null}. 210 * 211 * @return The actor. 212 * 213 * @throws ParseException If parsing failed. 214 */ 215 public static Actor parse(final JSONObject jsonObject) 216 throws ParseException { 217 218 Subject sub = new Subject(JSONObjectUtils.getNonBlankString(jsonObject, "sub")); 219 220 Issuer iss = null; 221 222 if (jsonObject.containsKey("iss")) { 223 iss = new Issuer(JSONObjectUtils.getNonBlankString(jsonObject, "iss")); 224 } 225 226 Actor parent = parseTopLevel(jsonObject); 227 228 return new Actor(sub, iss, parent); 229 } 230 231 232 /** 233 * Parses an actor from the specified top-level JSON object contains 234 * an optional actor JSON representation. 235 * 236 * <p>Simple example: 237 * 238 * <pre> 239 * { 240 * "aud" : "https://consumer.example.com", 241 * "iss" : "https://issuer.example.com", 242 * "exp" : 1443904177, 243 * "nbf" : 1443904077, 244 * "sub" : "[email protected]", 245 * "act" : { "sub" : "[email protected]" } 246 * } 247 * </pre> 248 * 249 * <p>With nesting: 250 * 251 * <pre> 252 * { 253 * "aud" : "https://backend.example.com", 254 * "iss" : "https://issuer.example.com", 255 * "exp" : 1443904100, 256 * "nbf" : 1443904000, 257 * "sub" : "[email protected]", 258 * "act" : { "sub" : "consumer.example.com-web-application", 259 * "iss" : "https://issuer.example.net", 260 * "act" : { "sub":"[email protected]" } } 261 * } 262 * </pre> 263 * 264 * @param jsonObject The top-level JSON object to parse. Must not be 265 * {@code null}. 266 * 267 * @return The actor, {@code null} if not specified. 268 * 269 * @throws ParseException If parsing failed. 270 */ 271 public static Actor parseTopLevel(final JSONObject jsonObject) 272 throws ParseException { 273 274 JSONObject actSpec = JSONObjectUtils.getJSONObject(jsonObject, "act", null); 275 276 if (actSpec == null) return null; 277 278 return parse(actSpec); 279 } 280}