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