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