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.openid.connect.sdk.claims;
019
020
021import java.net.URI;
022import java.util.Set;
023import java.util.UUID;
024
025import com.nimbusds.oauth2.sdk.token.AccessToken;
026import net.minidev.json.JSONObject;
027
028
029/**
030 * Distributed OpenID claims set.
031 *
032 * <p>Example distributed claims with an access token (included in a UserInfo
033 * response):
034 *
035 * <pre>
036 * {
037 *   "_claim_names"   : { "credit_score" : "src1" },
038 *   "_claim_sources" : { "src1" : { "endpoint"     : "https://creditagency.example.com/claims_here",
039 *                                   "access_token" : "ksj3n283dke" } }
040 * }
041 * </pre>
042 *
043 * <p>Example distributed claims without a specified access token (included in
044 * a UserInfo response):
045 *
046 * <pre>
047 * {
048 *   "_claim_names" : { "payment_info"     : "src2",
049 *                      "shipping_address" : "src2" },
050 *   "_claim_sources" : { "src2" : { "endpoint" : "https://bank.example.com/claim_source" } }
051 * }
052 * </pre>
053 *
054 * <p>Related specifications:
055 *
056 * <ul>
057 *     <li>OpenID Connect Core 1.0, sections 5.1 and 5.6.2.
058 * </ul>
059 */
060public class DistributedClaims extends ExternalClaims {
061        
062        
063        /**
064         * The claims source endpoint.
065         */
066        private final URI sourceEndpoint;
067        
068        
069        /**
070         * Access token for retrieving the claims at the source URI,
071         * {@code null} if not specified.
072         */
073        private final AccessToken accessToken;
074        
075        
076        /**
077         * Creates a new aggregated OpenID claims instance, the claims source
078         * identifier is set to a GUUID string.
079         *
080         * @param names          The claim names. Must not be {@code null} or
081         *                       empty.
082         * @param sourceEndpoint The claims source endpoint. Must not be
083         *                       {@code null}.
084         * @param accessToken    Access token for retrieving the claims at the
085         *                       source endpoint, {@code null} if not
086         *                       specified.
087         */
088        public DistributedClaims(final Set<String> names, final URI sourceEndpoint, final AccessToken accessToken) {
089                
090                this(UUID.randomUUID().toString(), names, sourceEndpoint, accessToken);
091        }
092        
093        
094        /**
095         * Creates a new aggregated OpenID claims instance.
096         *
097         * @param sourceID       Identifier for the claims source. Must not be
098         *                       {@code null} or empty string.
099         * @param names          The claim names. Must not be {@code null} or
100         *                       empty.
101         * @param sourceEndpoint The claims source endpoint. Must not be
102         *                       {@code null}.
103         * @param accessToken    Access token for retrieving the claims at the
104         *                       source endpoint, {@code null} if not
105         *                       specified.
106         */
107        public DistributedClaims(final String sourceID, final Set<String> names, final URI sourceEndpoint, final AccessToken accessToken) {
108                
109                super(sourceID, names);
110                
111                if (sourceEndpoint == null) {
112                        throw new IllegalArgumentException("The claims source URI must not be null");
113                }
114                
115                this.sourceEndpoint = sourceEndpoint;
116                
117                this.accessToken = accessToken;
118        }
119        
120        
121        /**
122         * Returns the claims source endpoint.
123         *
124         * @return The claims source endpoint.
125         */
126        public URI getSourceEndpoint() {
127                
128                return sourceEndpoint;
129        }
130        
131        
132        /**
133         * Returns the access token for retrieving the claims at the source
134         * endpoint.
135         *
136         * @return The access token for retrieving the claims at the source
137         *         endpoint, {@code null} if not specified.
138         */
139        public AccessToken getAccessToken() {
140                
141                return accessToken;
142        }
143        
144        
145        @Override
146        void mergeInto(final JSONObject jsonObject) {
147                
148                JSONObject claimNamesObject = new JSONObject();
149                
150                for (String name: getNames()) {
151                        claimNamesObject.put(name, getSourceID());
152                }
153                
154                if (jsonObject.containsKey("_claim_names")) {
155                        ((JSONObject) jsonObject.get("_claim_names")).putAll(claimNamesObject);
156                } else {
157                        jsonObject.put("_claim_names", claimNamesObject);
158                }
159                
160                JSONObject sourceSpec = new JSONObject();
161                sourceSpec.put("endpoint", getSourceEndpoint().toString());
162                if (getAccessToken() != null) {
163                        sourceSpec.put("access_token", getAccessToken().getValue());
164                }
165                JSONObject claimSourcesObject = new JSONObject();
166                claimSourcesObject.put(getSourceID(), sourceSpec);
167                
168                if (jsonObject.containsKey("_claim_sources")) {
169                        ((JSONObject) jsonObject.get("_claim_sources")).putAll(claimSourcesObject);
170                } else {
171                        jsonObject.put("_claim_sources", claimSourcesObject);
172                }
173        }
174}