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}