001/*
002 * oauth2-oidc-sdk
003 *
004 * Copyright 2012-2021, 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.ciba;
019
020
021import net.jcip.annotations.Immutable;
022import net.minidev.json.JSONObject;
023
024import com.nimbusds.common.contenttype.ContentType;
025import com.nimbusds.oauth2.sdk.ParseException;
026import com.nimbusds.oauth2.sdk.SuccessResponse;
027import com.nimbusds.oauth2.sdk.http.HTTPResponse;
028import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
029
030
031/**
032 * Successful CIBA request acknowledgement from an OpenID provider / OAuth 2.0
033 * authorisation server backend authentication endpoint.
034 *
035 * <p>Example HTTP response:
036 *
037 * <pre>
038 * HTTP/1.1 200 OK
039 * Content-Type: application/json
040 * Cache-Control: no-store
041 *
042 * {
043 *   "auth_req_id": "1c266114-a1be-4252-8ad1-04986c5b9ac1",
044 *   "expires_in": 120,
045 *   "interval": 2
046 * }
047 * </pre>
048 *
049 * <p>Related specifications:
050 *
051 * <ul>
052 *      <li>OpenID Connect CIBA Flow - Core 1.0, section 7.3.
053 * </ul>
054 */
055@Immutable
056public class CIBARequestAcknowledgement extends CIBAResponse implements SuccessResponse {
057        
058        
059        /**
060         * The default minimal wait interval in seconds for polling the token
061         * endpoint for the poll and ping delivery modes.
062         */
063        public static final int DEFAULT_MIN_WAIT_INTERVAL = 5;
064
065        
066        /**
067         * The CIBA request ID.
068         */
069        private final AuthRequestID authRequestID;
070        
071        
072        /**
073         * The expiration time of the CIBA request ID, in seconds.
074         */
075        private final int expiresIn;
076        
077        
078        /**
079         * The minimal wait interval in seconds for polling the token endpoint
080         * for the poll or ping delivery modes.
081         */
082        private final Integer minWaitInterval;
083        
084
085        /**
086         * Creates a new successful CIBA request acknowledgement.
087         * 
088         * @param authRequestID   The CIBA request ID.
089         * @param expiresIn       The expiration time of the CIBA request ID,
090         *                        in seconds. Must be positive.
091         * @param minWaitInterval The minimal wait interval in seconds for
092         *                        polling the token endpoint for the poll or
093         *                        ping delivery modes, {@code null} if not
094         *                        specified.
095         */
096        public CIBARequestAcknowledgement(final AuthRequestID authRequestID,
097                                          final int expiresIn,
098                                          final Integer minWaitInterval) {
099                
100                super();
101                
102                if (authRequestID == null) {
103                        throw new IllegalArgumentException("The auth_req_id must not be null");
104                }
105                this.authRequestID = authRequestID;
106                
107                if (expiresIn < 1) {
108                        throw new IllegalArgumentException("The expiration must be a positive integer");
109                }
110                this.expiresIn = expiresIn;
111
112                if (minWaitInterval != null && minWaitInterval < 1) {
113                        throw new IllegalArgumentException("The interval must be a positive integer");
114                }
115                this.minWaitInterval = minWaitInterval;
116        }
117        
118
119        @Override
120        public boolean indicatesSuccess() {
121                return true;
122        }
123        
124        
125        /**
126         * Returns the CIBA request ID.
127         *
128         * @return The CIBA request ID.
129         */
130        public AuthRequestID getAuthRequestID() {
131                return authRequestID;
132        }
133        
134        
135        /**
136         * Returns the expiration time of the CIBA request ID in seconds.
137         *
138         * @return The expiration time in seconds.
139         */
140        public int getExpiresIn() {
141                return expiresIn;
142        }
143        
144        
145        /**
146         * Returns the minimum wait interval in seconds for polling the token
147         * endpoint for the poll and ping delivery modes.
148         *
149         * @return The interval in seconds, {@code null} if not specified.
150         */
151        public Integer getMinWaitInterval() {
152                return minWaitInterval;
153        }
154        
155
156        /**
157         * Returns a JSON object representation of this CIBA request
158         * acknowledgement.
159         *
160         * @return The JSON object.
161         */
162        public JSONObject toJSONObject() {
163
164                JSONObject o = new JSONObject();
165                o.put("auth_req_id", authRequestID);
166                o.put("expires_in", expiresIn);
167                if (minWaitInterval != null) {
168                        o.put("interval", minWaitInterval);
169                }
170                return o;
171        }
172
173        
174        @Override
175        public HTTPResponse toHTTPResponse() {
176
177                HTTPResponse httpResponse = new HTTPResponse(HTTPResponse.SC_OK);
178                httpResponse.setEntityContentType(ContentType.APPLICATION_JSON);
179                httpResponse.setCacheControl("no-store");
180                httpResponse.setPragma("no-cache");
181                httpResponse.setContent(toJSONObject().toString());
182                return httpResponse;
183        }
184
185        
186        /**
187         * Parses a successful CIBA request acknowledgement from the specified
188         * JSON object.
189         *
190         * @param jsonObject The JSON object to parse. Must not be {@code null}.
191         *
192         * @return The CIBA request acknowledgement.
193         *
194         * @throws ParseException If parsing failed.
195         */
196        public static CIBARequestAcknowledgement parse(final JSONObject jsonObject)
197                throws ParseException {
198
199                AuthRequestID authRequestID = AuthRequestID.parse(JSONObjectUtils.getString(jsonObject, "auth_req_id"));
200                
201                int expiresIn = JSONObjectUtils.getInt(jsonObject, "expires_in");
202                
203                if (expiresIn < 1) {
204                        throw new ParseException("The expires_in parameter must be a positive integer");
205                }
206                
207                Integer minWaitInterval = null;
208                if (jsonObject.get("interval") != null) {
209                        minWaitInterval = JSONObjectUtils.getInt(jsonObject, "interval");
210                }
211                
212                if (minWaitInterval != null && minWaitInterval < 1) {
213                        throw new ParseException("The interval parameter must be a positive integer");
214                }
215                
216                return new CIBARequestAcknowledgement(authRequestID, expiresIn, minWaitInterval);
217        }
218        
219        
220        /**
221         * Parses a successful CIBA request acknowledgement from the specified
222         * HTTP response.
223         *
224         * @param httpResponse The HTTP response to parse. Must not be
225         *                     {@code null}.
226         *
227         * @return The CIBA request acknowledgement.
228         *
229         * @throws ParseException If parsing failed.
230         */
231        public static CIBARequestAcknowledgement parse(final HTTPResponse httpResponse)
232                throws ParseException {
233
234                httpResponse.ensureStatusCode(HTTPResponse.SC_OK);
235                JSONObject jsonObject = httpResponse.getContentAsJSONObject();
236                return parse(jsonObject);
237        }
238}