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