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.rp;
019
020
021import java.net.URI;
022import java.net.URISyntaxException;
023
024import net.jcip.annotations.Immutable;
025
026import org.apache.commons.lang3.StringUtils;
027
028import net.minidev.json.JSONObject;
029
030import com.nimbusds.jwt.SignedJWT;
031
032import com.nimbusds.oauth2.sdk.ParseException;
033import com.nimbusds.oauth2.sdk.client.ClientRegistrationRequest;
034import com.nimbusds.oauth2.sdk.http.HTTPRequest;
035import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
036import com.nimbusds.oauth2.sdk.util.JSONObjectUtils;
037
038
039/**
040 * OpenID Connect client registration request.
041 *
042 * <p>Example HTTP request:
043 *
044 * <pre>
045 * POST /connect/register HTTP/1.1
046 * Content-Type: application/json
047 * Accept: application/json
048 * Host: server.example.com
049 * Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJ ...
050 *
051 * {
052 *  "application_type"                : "web",
053 *  "redirect_uris"                   : [ "https://client.example.org/callback",
054 *                                        "https://client.example.org/callback2" ],
055 *  "client_name"                     : "My Example",
056 *  "client_name#ja-Jpan-JP"          : "クライアント名",
057 *  "logo_uri"                        : "https://client.example.org/logo.png",
058 *  "subject_type"                    : "pairwise",
059 *  "sector_identifier_uri"           : "https://other.example.net/file_of_redirect_uris.json",
060 *  "token_endpoint_auth_method"      : "client_secret_basic",
061 *  "jwks_uri"                        : "https://client.example.org/my_public_keys.jwks",
062 *  "userinfo_encrypted_response_alg" : "RSA1_5",
063 *  "userinfo_encrypted_response_enc" : "A128CBC-HS256",
064 *  "contacts"                        : [ "[email protected]", "[email protected]" ],
065 *  "request_uris"                    : [ "https://client.example.org/rf.txt#qpXaRLh_n93TTR9F252ValdatUQvQiJi5BDub2BeznA" ]
066 * }
067 * </pre>
068 *
069 * <p>Related specifications:
070 *
071 * <ul>
072 *     <li>OpenID Connect Dynamic Client Registration 1.0, section 3.1.
073 *     <li>OAuth 2.0 Dynamic Client Registration Protocol (RFC 7591), sections
074 *         2 and 3.1.
075 * </ul>
076 */
077@Immutable
078public class OIDCClientRegistrationRequest extends ClientRegistrationRequest {
079        
080        
081        /**
082         * Creates a new OpenID Connect client registration request.
083         *
084         * @param uri         The URI of the client registration endpoint. May 
085         *                    be {@code null} if the {@link #toHTTPRequest()}
086         *                    method will not be used.
087         * @param metadata    The OpenID Connect client metadata. Must not be 
088         *                    {@code null} and must specify one or more
089         *                    redirection URIs.
090         * @param accessToken An OAuth 2.0 Bearer access token for the request, 
091         *                    {@code null} if none.
092         */
093        public OIDCClientRegistrationRequest(final URI uri,
094                                             final OIDCClientMetadata metadata, 
095                                             final BearerAccessToken accessToken) {
096
097                super(uri, metadata, accessToken);
098        }
099
100
101        /**
102         * Creates a new OpenID Connect client registration request with an
103         * optional software statement.
104         *
105         * @param uri               The URI of the client registration
106         *                          endpoint. May be {@code null} if the
107         *                          {@link #toHTTPRequest()} method will not be
108         *                          used.
109         * @param metadata          The OpenID Connect client metadata. Must
110         *                          not be {@code null} and must specify one or
111         *                          more redirection URIs.
112         * @param softwareStatement Optional software statement, as a signed
113         *                          JWT with an {@code iss} claim; {@code null}
114         *                          if not specified.
115         * @param accessToken       An OAuth 2.0 Bearer access token for the
116         *                          request, {@code null} if none.
117         */
118        public OIDCClientRegistrationRequest(final URI uri,
119                                             final OIDCClientMetadata metadata,
120                                             final SignedJWT softwareStatement,
121                                             final BearerAccessToken accessToken) {
122
123                super(uri, metadata, softwareStatement, accessToken);
124        }
125        
126        
127        /**
128         * Gets the associated OpenID Connect client metadata.
129         *
130         * @return The OpenID Connect client metadata.
131         */
132        public OIDCClientMetadata getOIDCClientMetadata() {
133                
134                return (OIDCClientMetadata)getClientMetadata();
135        }
136        
137        
138        /**
139         * Parses an OpenID Connect client registration request from the 
140         * specified HTTP POST request.
141         *
142         * @param httpRequest The HTTP request. Must not be {@code null}.
143         *
144         * @return The OpenID Connect client registration request.
145         *
146         * @throws ParseException If the HTTP request couldn't be parsed to an 
147         *                        OpenID Connect client registration request.
148         */
149        public static OIDCClientRegistrationRequest parse(final HTTPRequest httpRequest)
150                throws ParseException {
151
152                httpRequest.ensureMethod(HTTPRequest.Method.POST);
153
154                // Get the JSON object content
155                JSONObject jsonObject = httpRequest.getQueryAsJSONObject();
156
157                // Extract the software statement if any
158                SignedJWT stmt = null;
159
160                if (jsonObject.containsKey("software_statement")) {
161
162                        try {
163                                stmt = SignedJWT.parse(JSONObjectUtils.getString(jsonObject, "software_statement"));
164
165                        } catch (java.text.ParseException e) {
166
167                                throw new ParseException("Invalid software statement JWT: " + e.getMessage());
168                        }
169
170                        // Prevent the JWT from appearing in the metadata
171                        jsonObject.remove("software_statement");
172                }
173
174                // Parse the client metadata
175                OIDCClientMetadata metadata = OIDCClientMetadata.parse(jsonObject);
176
177                // Parse the optional bearer access token
178                BearerAccessToken accessToken = null;
179                
180                String authzHeaderValue = httpRequest.getAuthorization();
181                
182                if (StringUtils.isNotBlank(authzHeaderValue))
183                        accessToken = BearerAccessToken.parse(authzHeaderValue);
184
185                try {
186                        URI endpointURI = httpRequest.getURL().toURI();
187
188                        return new OIDCClientRegistrationRequest(endpointURI, metadata, stmt, accessToken);
189
190                } catch (URISyntaxException | IllegalArgumentException e) {
191
192                        throw new ParseException(e.getMessage(), e);
193                }
194        }
195}