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