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 (RFC 7591), sections 057 * 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}