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.client; 019 020 021import java.util.Collections; 022import java.util.HashSet; 023import java.util.Set; 024 025import com.nimbusds.oauth2.sdk.ErrorObject; 026import com.nimbusds.oauth2.sdk.ErrorResponse; 027import com.nimbusds.oauth2.sdk.ParseException; 028import com.nimbusds.oauth2.sdk.http.CommonContentTypes; 029import com.nimbusds.oauth2.sdk.http.HTTPResponse; 030import com.nimbusds.oauth2.sdk.token.BearerTokenError; 031import com.nimbusds.oauth2.sdk.util.StringUtils; 032import net.jcip.annotations.Immutable; 033import net.minidev.json.JSONObject; 034 035 036/** 037 * Client registration error response. 038 * 039 * <p>Standard errors: 040 * 041 * <ul> 042 * <li>OAuth 2.0 Bearer Token errors: 043 * <ul> 044 * <li>{@link com.nimbusds.oauth2.sdk.token.BearerTokenError#MISSING_TOKEN} 045 * <li>{@link com.nimbusds.oauth2.sdk.token.BearerTokenError#INVALID_REQUEST} 046 * <li>{@link com.nimbusds.oauth2.sdk.token.BearerTokenError#INVALID_TOKEN} 047 * <li>{@link com.nimbusds.oauth2.sdk.token.BearerTokenError#INSUFFICIENT_SCOPE} 048 * </ul> 049 * <li>OpenID Connect specific errors: 050 * <ul> 051 * <li>{@link RegistrationError#INVALID_REDIRECT_URI} 052 * <li>{@link RegistrationError#INVALID_CLIENT_METADATA} 053 * <li>{@link RegistrationError#INVALID_SOFTWARE_STATEMENT} 054 * <li>{@link RegistrationError#UNAPPROVED_SOFTWARE_STATEMENT} 055 * </ul> 056 * </ul> 057 * 058 * <p>Example HTTP response: 059 * 060 * <pre> 061 * HTTP/1.1 400 Bad Request 062 * Content-Type: application/json 063 * Cache-Control: no-store 064 * Pragma: no-cache 065 * 066 * { 067 * "error":"invalid_redirect_uri", 068 * "error_description":"The redirection URI of http://sketchy.example.com is not allowed for this server." 069 * } 070 * </pre> 071 * 072 * <p>Related specifications: 073 * 074 * <ul> 075 * <li>OAuth 2.0 Dynamic Client Registration Protocol (RFC 7591), section 076 * 3.2.2. 077 * <li>OAuth 2.0 Bearer Token Usage (RFC 6750), section 3.1. 078 * </ul> 079 */ 080@Immutable 081public class ClientRegistrationErrorResponse 082 extends ClientRegistrationResponse 083 implements ErrorResponse { 084 085 086 /** 087 * Gets the standard errors for a client registration error response. 088 * 089 * @return The standard errors, as a read-only set. 090 */ 091 public static Set<ErrorObject> getStandardErrors() { 092 093 Set<ErrorObject> stdErrors = new HashSet<>(); 094 stdErrors.add(BearerTokenError.MISSING_TOKEN); 095 stdErrors.add(BearerTokenError.INVALID_REQUEST); 096 stdErrors.add(BearerTokenError.INVALID_TOKEN); 097 stdErrors.add(BearerTokenError.INSUFFICIENT_SCOPE); 098 stdErrors.add(RegistrationError.INVALID_REDIRECT_URI); 099 stdErrors.add(RegistrationError.INVALID_CLIENT_METADATA); 100 stdErrors.add(RegistrationError.INVALID_SOFTWARE_STATEMENT); 101 stdErrors.add(RegistrationError.UNAPPROVED_SOFTWARE_STATEMENT); 102 103 return Collections.unmodifiableSet(stdErrors); 104 } 105 106 107 /** 108 * The underlying error. 109 */ 110 private final ErrorObject error; 111 112 113 /** 114 * Creates a new client registration error response. 115 * 116 * @param error The error. Should match one of the 117 * {@link #getStandardErrors standard errors} for a client 118 * registration error response. Must not be {@code null}. 119 */ 120 public ClientRegistrationErrorResponse(final ErrorObject error) { 121 122 if (error == null) 123 throw new IllegalArgumentException("The error must not be null"); 124 125 this.error = error; 126 } 127 128 129 @Override 130 public boolean indicatesSuccess() { 131 132 return false; 133 } 134 135 136 @Override 137 public ErrorObject getErrorObject() { 138 139 return error; 140 } 141 142 143 /** 144 * Returns the HTTP response for this client registration error 145 * response. 146 * 147 * <p>Example HTTP response: 148 * 149 * <pre> 150 * HTTP/1.1 400 Bad Request 151 * Content-Type: application/json 152 * Cache-Control: no-store 153 * Pragma: no-cache 154 * 155 * { 156 * "error":"invalid_redirect_uri", 157 * "error_description":"The redirection URI of http://sketchy.example.com is not allowed for this server." 158 * } 159 * </pre> 160 * 161 * @return The HTTP response. 162 */ 163 @Override 164 public HTTPResponse toHTTPResponse() { 165 166 HTTPResponse httpResponse; 167 168 if (error.getHTTPStatusCode() > 0) { 169 httpResponse = new HTTPResponse(error.getHTTPStatusCode()); 170 } else { 171 httpResponse = new HTTPResponse(HTTPResponse.SC_BAD_REQUEST); 172 } 173 174 // Add the WWW-Authenticate header 175 if (error instanceof BearerTokenError) { 176 177 BearerTokenError bte = (BearerTokenError)error; 178 179 httpResponse.setWWWAuthenticate(bte.toWWWAuthenticateHeader()); 180 181 } else { 182 JSONObject jsonObject = new JSONObject(); 183 184 if (error.getCode() != null) 185 jsonObject.put("error", error.getCode()); 186 187 if (error.getDescription() != null) 188 jsonObject.put("error_description", error.getDescription()); 189 190 httpResponse.setContentType(CommonContentTypes.APPLICATION_JSON); 191 192 httpResponse.setContent(jsonObject.toString()); 193 } 194 195 httpResponse.setCacheControl("no-store"); 196 httpResponse.setPragma("no-cache"); 197 198 return httpResponse; 199 } 200 201 202 /** 203 * Parses a client registration error response from the specified HTTP 204 * response. 205 * 206 * <p>Note: The HTTP status code is not checked for matching the error 207 * code semantics. 208 * 209 * @param httpResponse The HTTP response to parse. Its status code must 210 * not be 200 (OK). Must not be {@code null}. 211 * 212 * @throws ParseException If the HTTP response couldn't be parsed to a 213 * client registration error response. 214 */ 215 public static ClientRegistrationErrorResponse parse(final HTTPResponse httpResponse) 216 throws ParseException { 217 218 httpResponse.ensureStatusCodeNotOK(); 219 220 ErrorObject error; 221 222 String wwwAuth = httpResponse.getWWWAuthenticate(); 223 224 if (StringUtils.isNotBlank(wwwAuth)) { 225 error = BearerTokenError.parse(wwwAuth); 226 } else { 227 error = ErrorObject.parse(httpResponse); 228 } 229 230 return new ClientRegistrationErrorResponse(error); 231 } 232}