001package com.nimbusds.oauth2.sdk.client;
002
003
004import java.net.MalformedURLException;
005import java.net.URI;
006import java.net.URISyntaxException;
007import java.net.URL;
008
009import org.apache.commons.lang3.StringUtils;
010
011import net.jcip.annotations.Immutable;
012
013import net.minidev.json.JSONObject;
014
015import com.nimbusds.oauth2.sdk.ParseException;
016import com.nimbusds.oauth2.sdk.ProtectedResourceRequest;
017import com.nimbusds.oauth2.sdk.SerializeException;
018import com.nimbusds.oauth2.sdk.http.CommonContentTypes;
019import com.nimbusds.oauth2.sdk.http.HTTPRequest;
020import com.nimbusds.oauth2.sdk.token.BearerAccessToken;
021
022
023/**
024 * Client registration request.
025 *
026 * <p>Example HTTP request:
027 *
028 * <pre>
029 * POST /register HTTP/1.1
030 * Content-Type: application/json
031 * Accept: application/json
032 * Authorization: Bearer ey23f2.adfj230.af32-developer321
033 * Host: server.example.com
034 *
035 * {
036 *  "redirect_uris"              : ["https://client.example.org/callback", 
037 *                                  "https://client.example.org/callback2"],
038 *  "client_name"                : "My Example Client",
039 *  "client_name#ja-Jpan-JP"     : "\u30AF\u30E9\u30A4\u30A2\u30F3\u30C8\u540D",
040 *  "token_endpoint_auth_method" : "client_secret_basic",
041 *  "scope"                      : "read write dolphin",
042 *  "logo_uri"                   : "https://client.example.org/logo.png",
043 *  "jwks_uri"                   : "https://client.example.org/my_public_keys.jwks"
044 * }
045 * </pre>
046 *
047 * <p>Related specifications:
048 *
049 * <ul>
050 *     <li>OAuth 2.0 Dynamic Client Registration Protocol 
051 *         (draft-ietf-oauth-dyn-reg-14), section 3.1.
052 * </ul>
053 */
054@Immutable
055public class ClientRegistrationRequest extends ProtectedResourceRequest {
056
057
058        /**
059         * The client metadata.
060         */
061        private final ClientMetadata metadata;
062
063
064        /**
065         * Creates a new 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 client metadata. Must not be {@code null} and 
071         *                    must specify one or more redirection URIs.
072         * @param accessToken An OAuth 2.0 Bearer access token for the request, 
073         *                    {@code null} if none.
074         */
075        public ClientRegistrationRequest(final URI uri,
076                                         final ClientMetadata metadata, 
077                                         final BearerAccessToken accessToken) {
078
079                super(uri, accessToken);
080
081                if (metadata == null)
082                        throw new IllegalArgumentException("The client metadata must not be null");
083                
084                this.metadata = metadata;
085        }
086
087
088        /**
089         * Gets the associated client metadata.
090         *
091         * @return The client metadata.
092         */
093        public ClientMetadata getClientMetadata() {
094
095                return metadata;
096        }
097
098
099        @Override
100        public HTTPRequest toHTTPRequest()
101                throws SerializeException{
102                
103                if (getEndpointURI() == null)
104                        throw new SerializeException("The endpoint URI is not specified");
105
106                URL endpointURL;
107
108                try {
109                        endpointURL = getEndpointURI().toURL();
110
111                } catch (MalformedURLException e) {
112                        throw new SerializeException(e.getMessage(), e);
113                }
114        
115                HTTPRequest httpRequest = new HTTPRequest(HTTPRequest.Method.POST, endpointURL);
116
117                if (getAccessToken() != null)
118                        httpRequest.setAuthorization(getAccessToken().toAuthorizationHeader());
119
120                httpRequest.setContentType(CommonContentTypes.APPLICATION_JSON);
121
122                httpRequest.setQuery(metadata.toJSONObject().toString());
123
124                return httpRequest;
125        }
126
127
128        /**
129         * Parses a client registration request from the specified HTTP POST 
130         * request.
131         *
132         * @param httpRequest The HTTP request. Must not be {@code null}.
133         *
134         * @return The client registration request.
135         *
136         * @throws ParseException If the HTTP request couldn't be parsed to a 
137         *                        client registration request.
138         */
139        public static ClientRegistrationRequest parse(final HTTPRequest httpRequest)
140                throws ParseException {
141
142                httpRequest.ensureMethod(HTTPRequest.Method.POST);
143
144                // Parse the client metadata
145                JSONObject jsonObject = httpRequest.getQueryAsJSONObject();
146
147                ClientMetadata metadata = ClientMetadata.parse(jsonObject);
148
149                // Parse the optional bearer access token
150                BearerAccessToken accessToken = null;
151                
152                String authzHeaderValue = httpRequest.getAuthorization();
153                
154                if (StringUtils.isNotBlank(authzHeaderValue))
155                        accessToken = BearerAccessToken.parse(authzHeaderValue);
156
157                URI endpointURI;
158
159                try {
160                        endpointURI = httpRequest.getURL().toURI();
161
162                } catch (URISyntaxException e) {
163
164                        throw new ParseException(e.getMessage(), e);
165                }
166                
167                return new ClientRegistrationRequest(endpointURI, metadata, accessToken);
168        }
169}