001/*
002 * oauth2-oidc-sdk
003 *
004 * Copyright 2012-2020, 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.federation.api;
019
020
021import java.net.URI;
022import java.util.Collections;
023import java.util.LinkedHashMap;
024import java.util.List;
025import java.util.Map;
026
027import net.jcip.annotations.Immutable;
028
029import com.nimbusds.oauth2.sdk.ParseException;
030import com.nimbusds.oauth2.sdk.http.HTTPRequest;
031import com.nimbusds.oauth2.sdk.util.MultivaluedMapUtils;
032import com.nimbusds.oauth2.sdk.util.StringUtils;
033import com.nimbusds.openid.connect.sdk.federation.entities.EntityID;
034import com.nimbusds.openid.connect.sdk.federation.entities.FederationMetadataType;
035
036
037/**
038 * Trust negotiation request.
039 *
040 * <p>Related specifications:
041 *
042 * <ul>
043 *     <li>OpenID Connect Federation 1.0, section 6.2.1.
044 * </ul>
045 */
046@Immutable
047public class TrustNegotiationRequest extends FederationAPIRequest {
048        
049        
050        /**
051         * The respondent.
052         */
053        private final EntityID respondent;
054        
055        
056        /**
057         * The peer.
058         */
059        private final EntityID peer;
060        
061        
062        /**
063         * The metadata type.
064         */
065        private final FederationMetadataType metadataType;
066        
067        
068        /**
069         * The trust anchor.
070         */
071        private final EntityID anchor;
072        
073        
074        /**
075         * Creates a new trust negotiation request.
076         *
077         * @param endpoint     The federation API endpoint. Must not be
078         *                     {@code null}.
079         * @param respondent   The respondent. Must not be {@code null}.
080         * @param peer         The peer. Must not be {@code null}.
081         * @param metadataType The metadata type to resolve. Must not be
082         *                     {@code null}.
083         * @param anchor       The trust anchor. Must not be {@code null}.
084         */
085        public TrustNegotiationRequest(final URI endpoint,
086                                       final EntityID respondent,
087                                       final EntityID peer,
088                                       final FederationMetadataType metadataType,
089                                       final EntityID anchor) {
090                
091                super(endpoint, OperationType.RESOLVE_METADATA);
092                
093                if (respondent == null) {
094                        throw new IllegalArgumentException("The respondent must not be null");
095                }
096                this.respondent = respondent;
097                
098                if (peer == null) {
099                        throw new IllegalArgumentException("The peer must not be null");
100                }
101                this.peer = peer;
102                
103                if (metadataType == null) {
104                        throw new IllegalArgumentException("The metadata type must not be null");
105                }
106                this.metadataType = metadataType;
107                
108                if (anchor == null) {
109                        throw new IllegalArgumentException("The anchor must not be null");
110                }
111                this.anchor = anchor;
112        }
113        
114        
115        /**
116         * Returns the respondent.
117         *
118         * @return The respondent.
119         */
120        public EntityID getRespondent() {
121                return respondent;
122        }
123        
124        
125        /**
126         * Returns the peer.
127         *
128         * @return The peer.
129         */
130        public EntityID getPeer() {
131                return peer;
132        }
133        
134        
135        /**
136         * Returns the metadata type.
137         *
138         * @return The metadata type to resolve.
139         */
140        public FederationMetadataType getMetadataType() {
141                return metadataType;
142        }
143        
144        
145        /**
146         * Returns the trust anchor.
147         *
148         * @return The trust anchor.
149         */
150        public EntityID getTrustAnchor() {
151                return anchor;
152        }
153        
154        
155        @Override
156        public Map<String, List<String>> toParameters() {
157                Map<String, List<String>> params = new LinkedHashMap<>();
158                params.put("operation", Collections.singletonList(getOperationType().getValue()));
159                params.put("respondent", Collections.singletonList(getRespondent().getValue()));
160                params.put("peer", Collections.singletonList(getPeer().getValue()));
161                params.put("type", Collections.singletonList(getMetadataType().getValue()));
162                params.put("anchor", Collections.singletonList(getTrustAnchor().getValue()));
163                return params;
164        }
165        
166        
167        /**
168         * Parses a trust negotiation request from the specified query string
169         * parameters.
170         *
171         * @param params The query string parameters. Must not be {@code null}.
172         *
173         * @return The trust negotiation request.
174         *
175         * @throws ParseException If parsing failed.
176         */
177        public static TrustNegotiationRequest parse(final Map<String, List<String>> params)
178                throws ParseException {
179                
180                String value = MultivaluedMapUtils.getFirstValue(params, "operation");
181                if (StringUtils.isBlank(value)) {
182                        throw new ParseException("Missing operation type");
183                }
184                if (! OperationType.RESOLVE_METADATA.getValue().equals(value)) {
185                        throw new ParseException("The operation type must be " + OperationType.RESOLVE_METADATA);
186                }
187                
188                value = MultivaluedMapUtils.getFirstValue(params, "respondent");
189                if (StringUtils.isBlank(value)) {
190                        throw new ParseException("Missing respondent");
191                }
192                EntityID respondent = new EntityID(value);
193                
194                value = MultivaluedMapUtils.getFirstValue(params, "peer");
195                if (StringUtils.isBlank(value)) {
196                        throw new ParseException("Missing peer");
197                }
198                EntityID peer = new EntityID(value);
199                
200                value = MultivaluedMapUtils.getFirstValue(params, "type");
201                if (StringUtils.isBlank(value)) {
202                        throw new ParseException("Missing metadata type");
203                }
204                FederationMetadataType metadataType = new FederationMetadataType(value);
205                
206                value = MultivaluedMapUtils.getFirstValue(params, "anchor");
207                if (StringUtils.isBlank(value)) {
208                        throw new ParseException("Missing anchor");
209                }
210                EntityID anchor = new EntityID(value);
211                
212                return new TrustNegotiationRequest(null, respondent, peer, metadataType, anchor);
213        }
214        
215        
216        /**
217         * Parses a trust negotiation request from the specified HTTP request.
218         *
219         * @param httpRequest The HTTP request. Must not be {@code null}.
220         *
221         * @return The trust negotiation request.
222         *
223         * @throws ParseException If parsing failed.
224         */
225        public static TrustNegotiationRequest parse(final HTTPRequest httpRequest)
226                throws ParseException {
227                
228                httpRequest.ensureMethod(HTTPRequest.Method.GET);
229                
230                TrustNegotiationRequest request = TrustNegotiationRequest.parse(httpRequest.getQueryParameters());
231                
232                return new TrustNegotiationRequest(
233                        httpRequest.getURI(),
234                        request.respondent,
235                        request.getPeer(),
236                        request.getMetadataType(),
237                        request.getTrustAnchor());
238        }
239}