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.oauth2.sdk; 019 020 021import com.nimbusds.common.contenttype.ContentType; 022import com.nimbusds.jwt.JWT; 023import com.nimbusds.jwt.JWTParser; 024import com.nimbusds.jwt.PlainJWT; 025import com.nimbusds.oauth2.sdk.auth.PKITLSClientAuthentication; 026import com.nimbusds.oauth2.sdk.auth.SelfSignedTLSClientAuthentication; 027import com.nimbusds.oauth2.sdk.auth.TLSClientAuthentication; 028import com.nimbusds.oauth2.sdk.http.HTTPRequest; 029import com.nimbusds.oauth2.sdk.id.ClientID; 030import com.nimbusds.oauth2.sdk.util.JSONObjectUtils; 031import net.jcip.annotations.Immutable; 032import net.minidev.json.JSONObject; 033 034import java.net.URI; 035import java.util.Objects; 036 037 038/** 039 * Request object POST request. 040 * 041 * <p>Example request object POST request: 042 * 043 * <pre> 044 * POST /requests HTTP/1.1 045 * Host: c2id.com 046 * Content-Type: application/jws 047 * Content-Length: 1288 048 * 049 * eyJhbGciOiJSUzI1NiIsImtpZCI6ImsyYmRjIn0.ew0KICJpc3MiOiA 050 * (... abbreviated for brevity ...) 051 * zCYIb_NMXvtTIVc1jpspnTSD7xMbpL-2QgwUsAlMGzw 052 * </pre> 053 * 054 * <p>Related specifications: 055 * 056 * <ul> 057 * <li>Financial-grade API - Part 2: Read and Write API Security Profile 058 * <li>The OAuth 2.0 Authorization Framework: JWT Secured Authorization 059 * Request (JAR) (RFC 9101) 060 * </ul> 061 */ 062@Deprecated 063@Immutable 064public final class RequestObjectPOSTRequest extends AbstractOptionallyAuthenticatedRequest { 065 066 067 /** 068 * The request object as JWT, {@code null} for a 069 * {@link #requestJSONObject plain JSON object}. 070 */ 071 private final JWT requestObject; 072 073 074 /** 075 * The request parameters as plain JSON object, {@code null} for 076 * {@link #requestObject JWT}. 077 */ 078 private final JSONObject requestJSONObject; 079 080 081 /** 082 * Creates a new request object POST request. 083 * 084 * @param endpoint The URI of the request object endpoint. May be 085 * {@code null} if the {@link #toHTTPRequest} 086 * method is not going to be used. 087 * @param requestObject The request object. Must not be {@code null}. 088 */ 089 public RequestObjectPOSTRequest(final URI endpoint, 090 final JWT requestObject) { 091 092 super(endpoint, null); 093 094 this.requestObject = Objects.requireNonNull(requestObject); 095 096 if (requestObject instanceof PlainJWT) { 097 throw new IllegalArgumentException("The request object must not be an unsecured JWT (alg=none)"); 098 } 099 100 requestJSONObject = null; 101 } 102 103 104 /** 105 * Creates a new request object POST request where the parameters are 106 * submitted as plain JSON object, and the client authenticates by 107 * means of mutual TLS. TLS also ensures the integrity and 108 * confidentiality of the request parameters. This method is not 109 * standard. 110 * 111 * @param endpoint The URI of the request object endpoint. May 112 * be {@code null} if the 113 * {@link #toHTTPRequest} method is not going 114 * to be used. 115 * @param tlsClientAuth The mutual TLS client authentication. Must 116 * not be {@code null}. 117 * @param requestJSONObject The request parameters as plain JSON 118 * object. Must not be {@code null}. 119 */ 120 public RequestObjectPOSTRequest(final URI endpoint, 121 final TLSClientAuthentication tlsClientAuth, 122 final JSONObject requestJSONObject) { 123 124 super(endpoint, Objects.requireNonNull(tlsClientAuth)); 125 this.requestJSONObject = Objects.requireNonNull(requestJSONObject); 126 requestObject = null; 127 } 128 129 130 /** 131 * Returns the request object as JWT. 132 * 133 * @return The request object as JWT, {@code null} if the request 134 * parameters are specified as {@link #getRequestJSONObject() 135 * plain JSON object} instead. 136 */ 137 public JWT getRequestObject() { 138 139 return requestObject; 140 } 141 142 143 /** 144 * Returns the request object as plain JSON object. 145 * 146 * @return The request parameters as plain JSON object, {@code null} 147 * if the request object is specified as a 148 * {@link #getRequestObject() JWT}. 149 */ 150 public JSONObject getRequestJSONObject() { 151 152 return requestJSONObject; 153 } 154 155 156 /** 157 * Returns the mutual TLS client authentication. 158 * 159 * @return The mutual TLS client authentication. 160 */ 161 public TLSClientAuthentication getTLSClientAuthentication() { 162 163 return (TLSClientAuthentication) getClientAuthentication(); 164 } 165 166 167 @Override 168 public HTTPRequest toHTTPRequest() { 169 170 if (getEndpointURI() == null) 171 throw new SerializeException("The endpoint URI is not specified"); 172 173 HTTPRequest httpRequest = new HTTPRequest(HTTPRequest.Method.POST, getEndpointURI()); 174 175 if (getRequestObject() != null) { 176 httpRequest.setEntityContentType(ContentType.APPLICATION_JWT); 177 httpRequest.setBody(getRequestObject().serialize()); 178 } else if (getRequestJSONObject() != null) { 179 httpRequest.setEntityContentType(ContentType.APPLICATION_JSON); 180 httpRequest.setBody(getRequestJSONObject().toJSONString()); 181 getTLSClientAuthentication().applyTo(httpRequest); 182 } 183 184 return httpRequest; 185 } 186 187 188 /** 189 * Parses a request object POST request from the specified HTTP 190 * request. 191 * 192 * @param httpRequest The HTTP request. Must not be {@code null}. 193 * 194 * @return The request object POST request. 195 * 196 * @throws ParseException If the HTTP request couldn't be parsed to a 197 * request object POST request. 198 */ 199 public static RequestObjectPOSTRequest parse(final HTTPRequest httpRequest) 200 throws ParseException { 201 202 // Only HTTP POST accepted 203 httpRequest.ensureMethod(HTTPRequest.Method.POST); 204 205 if (httpRequest.getEntityContentType() == null) { 206 throw new ParseException("Missing Content-Type"); 207 } 208 209 if ( 210 ContentType.APPLICATION_JOSE.matches(httpRequest.getEntityContentType()) || 211 ContentType.APPLICATION_JWT.matches(httpRequest.getEntityContentType())) { 212 213 // Signed or signed and encrypted request object 214 215 JWT requestObject; 216 try { 217 requestObject = JWTParser.parse(httpRequest.getQuery()); 218 } catch (java.text.ParseException e) { 219 throw new ParseException("Invalid request object JWT: " + e.getMessage()); 220 } 221 222 if (requestObject instanceof PlainJWT) { 223 throw new ParseException("The request object is an unsecured JWT (alg=none)"); 224 } 225 226 return new RequestObjectPOSTRequest(httpRequest.getURI(), requestObject); 227 228 } else if (ContentType.APPLICATION_JSON.matches(httpRequest.getEntityContentType())) { 229 230 JSONObject jsonObject = httpRequest.getQueryAsJSONObject(); 231 232 if (jsonObject.get("client_id") == null) { 233 throw new ParseException("Missing client_id in JSON object"); 234 } 235 236 ClientID clientID = new ClientID(JSONObjectUtils.getNonBlankString(jsonObject, "client_id")); 237 238 TLSClientAuthentication tlsClientAuth; 239 if (httpRequest.getClientX509Certificate() != null && httpRequest.getClientX509CertificateSubjectDN() != null && 240 httpRequest.getClientX509CertificateSubjectDN().equals(httpRequest.getClientX509CertificateRootDN())) { 241 tlsClientAuth = new SelfSignedTLSClientAuthentication(clientID, httpRequest.getClientX509Certificate()); 242 } else if (httpRequest.getClientX509Certificate() != null) { 243 tlsClientAuth = new PKITLSClientAuthentication(clientID, httpRequest.getClientX509Certificate()); 244 } else { 245 throw new ParseException("Missing mutual TLS client authentication"); 246 } 247 248 return new RequestObjectPOSTRequest(httpRequest.getURI(), tlsClientAuth, jsonObject); 249 250 } else { 251 252 throw new ParseException("Unexpected Content-Type: " + httpRequest.getEntityContentType()); 253 } 254 } 255}