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