client refactoring, and javadocing

pull/59/head M-1
U-MITRE\mjwalsh 2012-03-26 14:18:54 -04:00
parent b8c953281e
commit c84c751991
1 changed files with 373 additions and 333 deletions

View File

@ -9,13 +9,13 @@ import java.security.KeyPair;
import java.security.KeyPairGenerator; import java.security.KeyPairGenerator;
import java.security.PrivateKey; import java.security.PrivateKey;
import java.security.PublicKey; import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature; import java.security.Signature;
import java.util.Arrays; import java.util.Arrays;
import java.util.Enumeration; import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Random;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
@ -23,8 +23,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Base64;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.HttpClient; import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.client.DefaultHttpClient;
import org.mitre.openid.connect.model.IdToken; import org.mitre.openid.connect.model.IdToken;
@ -33,6 +31,7 @@ import org.springframework.security.authentication.AuthenticationServiceExceptio
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.util.Assert;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap; import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.HttpClientErrorException;
@ -93,21 +92,78 @@ public class OpenIdConnectAuthenticationFilter extends
private final static String NONCE_SIGNATURE_COOKIE_NAME = "nonce"; private final static String NONCE_SIGNATURE_COOKIE_NAME = "nonce";
private final static String FILTER_PROCESSES_URL = "/openid_connect_login"; private final static String FILTER_PROCESSES_URL = "/openid_connect_login";
/**
* Builds the redirect_uri that will be sent to the Authorization Endpoint.
* By default returns the URL of the current request minus zero or more
* fields of the URL's query string.
*
* @param request
* the current request which is being processed by this filter
* @param ignoreFields
* an array of field names to ignore.
* @return a URL built from the messaged parameters.
*/
public static String buildRedirectURI(HttpServletRequest request,
String[] ignoreFields) {
List<String> ignore = (ignoreFields != null) ? Arrays
.asList(ignoreFields) : null;
boolean isFirst = true;
StringBuffer sb = request.getRequestURL();
for (Enumeration<?> e = request.getParameterNames(); e
.hasMoreElements();) {
String name = (String) e.nextElement();
if ((ignore == null) || (!ignore.contains(name))) {
// Assume for simplicity that there is only one value
String value = request.getParameter(name);
if (value == null) {
continue;
}
if (isFirst) {
sb.append("?");
isFirst = false;
}
sb.append(name).append("=").append(value);
if (e.hasMoreElements()) {
sb.append("&");
}
}
}
return sb.toString();
}
/** /**
* Return the URL w/ GET parameters * Return the URL w/ GET parameters
* *
* @param baseURI * @param baseURI
* @param params * A String containing the protocol, server address, path, and
* @return * program as per "http://server/path/program"
* @param queryStringFields
* A map where each key is the field name and the associated
* key's value is the field value used to populate the URL's
* query string
* @return A String representing the URL in form of
* http://server/path/program?query_string from the messaged
* parameters.
*/ */
public static String buildURL(String baseURI, public static String buildURL(String baseURI,
Map<String, String> urlVariables) { Map<String, String> queryStringFields) {
StringBuilder URLBuilder = new StringBuilder(baseURI); StringBuilder URLBuilder = new StringBuilder(baseURI);
char appendChar = '?'; char appendChar = '?';
for (Map.Entry<String, String> param : urlVariables.entrySet()) { for (Map.Entry<String, String> param : queryStringFields.entrySet()) {
try { try {
URLBuilder.append(appendChar).append(param.getKey()) URLBuilder.append(appendChar).append(param.getKey())
.append('=') .append('=')
@ -124,7 +180,13 @@ public class OpenIdConnectAuthenticationFilter extends
/** /**
* Returns the signature text for the byte array of data * Returns the signature text for the byte array of data
* *
* @return * @param signer
* The algorithm to sign with
* @param privateKey
* The private key to sign with
* @param data
* The data to be signed
* @return The signature text
*/ */
public static String sign(Signature signer, PrivateKey privateKey, public static String sign(Signature signer, PrivateKey privateKey,
byte[] data) { byte[] data) {
@ -151,8 +213,10 @@ public class OpenIdConnectAuthenticationFilter extends
* Verifies the signature text against the data * Verifies the signature text against the data
* *
* @param data * @param data
* The data
* @param sigText * @param sigText
* @return * The signature text
* @return True if valid, false if not
*/ */
public static boolean verify(Signature signer, PublicKey publicKey, public static boolean verify(Signature signer, PublicKey publicKey,
String data, String sigText) { String data, String sigText) {
@ -197,7 +261,7 @@ public class OpenIdConnectAuthenticationFilter extends
private Signature signer; private Signature signer;
/** /**
* * OpenIdConnectAuthenticationFilter constructor
*/ */
protected OpenIdConnectAuthenticationFilter() { protected OpenIdConnectAuthenticationFilter() {
super(FILTER_PROCESSES_URL); super(FILTER_PROCESSES_URL);
@ -213,34 +277,21 @@ public class OpenIdConnectAuthenticationFilter extends
public void afterPropertiesSet() { public void afterPropertiesSet() {
super.afterPropertiesSet(); super.afterPropertiesSet();
if (errorRedirectURI == null) { Assert.notNull(errorRedirectURI,
throw new IllegalArgumentException( "An Error Redirect URI must be supplied");
"An Error Redirect URI must be supplied");
}
if (authorizationEndpointURI == null) { Assert.notNull(authorizationEndpointURI,
throw new IllegalArgumentException( "An Authorization Endpoint URI must be supplied");
"An Authorization Endpoint URI must be supplied");
}
if (tokenEndpointURI == null) { Assert.notNull(tokenEndpointURI,
throw new IllegalArgumentException( "A Token ID Endpoint URI must be supplied");
"A Token ID Endpoint URI must be supplied");
}
if (checkIDEndpointURI == null) { Assert.notNull(checkIDEndpointURI,
throw new IllegalArgumentException( "A Check ID Endpoint URI must be supplied");
"A Check ID Endpoint URI must be supplied");
}
if (clientId == null) { Assert.notNull(clientId, "A Client ID must be supplied");
throw new IllegalArgumentException("A Client ID must be supplied");
}
if (clientSecret == null) { Assert.notNull(clientSecret, "A Client Secret must be supplied");
throw new IllegalArgumentException(
"A Client Secret must be supplied");
}
KeyPairGenerator keyPairGenerator; KeyPairGenerator keyPairGenerator;
try { try {
@ -256,19 +307,11 @@ public class OpenIdConnectAuthenticationFilter extends
throw new IllegalStateException(generalSecurityException); throw new IllegalStateException(generalSecurityException);
} }
// prepend the spec necessary scope // prepend the spec necessary SCOPE
setScope((scope != null && !scope.isEmpty()) ? SCOPE + " " + scope setScope((scope != null && !scope.isEmpty()) ? SCOPE + " " + scope
: SCOPE); : SCOPE);
} }
/*
* (non-Javadoc)
*
* @see org.springframework.security.web.authentication.
* AbstractAuthenticationProcessingFilter
* #attemptAuthentication(javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse)
*/
/* /*
* (non-Javadoc) * (non-Javadoc)
* *
@ -282,278 +325,22 @@ public class OpenIdConnectAuthenticationFilter extends
HttpServletResponse response) throws AuthenticationException, HttpServletResponse response) throws AuthenticationException,
IOException, ServletException { IOException, ServletException {
final boolean debug = logger.isDebugEnabled();
if (request.getParameter("error") != null) { if (request.getParameter("error") != null) {
// Handle Authorization Endpoint error handleError(request, response);
String error = request.getParameter("error");
String errorDescription = request.getParameter("error_description");
String errorURI = request.getParameter("error_uri");
Map<String, String> requestParams = new HashMap<String, String>();
requestParams.put("error", error);
if (errorDescription != null) {
requestParams.put("error_description", errorDescription);
}
if (errorURI != null) {
requestParams.put("error_uri", errorURI);
}
response.sendRedirect(buildURL(errorRedirectURI, requestParams));
} else { } else {
// Determine if the Authorization Endpoint issued an // Determine if the Authorization Endpoint issued an
// authorization grant // authorization grant
String authorizationGrant = request.getParameter("code"); if (request.getParameter("code") != null) {
if (authorizationGrant != null) { return handleAuthorizationGrantResponse(request);
// Handle Token Endpoint interaction
HttpClient httpClient = new DefaultHttpClient();
httpClient.getParams().setParameter("http.socket.timeout",
new Integer(httpSocketTimeout));
//
// TODO: basic auth is untested (it wasn't working last I tested)
// UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(
// clientId, clientSecret);
// ((DefaultHttpClient) httpClient).getCredentialsProvider()
// .setCredentials(AuthScope.ANY, credentials);
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(
httpClient);
RestTemplate restTemplate = new RestTemplate(factory);
MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
form.add("grant_type", "authorization_code");
form.add("code", authorizationGrant);
form.add("redirect_uri",
buildRedirectURI(request, new String[] { "code" }));
// pass clientId and clientSecret in post of request
form.add("client_id", clientId);
form.add("client_secret", clientSecret);
if (debug) {
logger.debug("tokenEndpointURI = " + tokenEndpointURI);
logger.debug("form = " + form);
}
String jsonString = null;
try {
jsonString = restTemplate.postForObject(tokenEndpointURI,
form, String.class);
} catch (HttpClientErrorException httpClientErrorException) {
// Handle error
logger.error("Token Endpoint error response: "
+ httpClientErrorException.getStatusText() + " : "
+ httpClientErrorException.getMessage());
throw new AuthenticationServiceException(
"Unable to obtain Access Token.");
}
JsonElement jsonRoot = new JsonParser().parse(jsonString);
if (jsonRoot.getAsJsonObject().get("error") != null) {
// Handle error
String error = jsonRoot.getAsJsonObject().get("error")
.getAsString();
logger.error("Token Endpoint returned: " + error);
throw new AuthenticationServiceException(
"Unable to obtain Access Token. Token Endpoint returned: "
+ error);
} else {
// Extract the id_token to insert into the
// OpenIdConnectAuthenticationToken
IdToken idToken = null;
if (jsonRoot.getAsJsonObject().get("id_token") != null) {
try {
idToken = IdToken.parse(jsonRoot.getAsJsonObject()
.get("id_token").getAsString());
} catch (Exception e) {
// I suspect this could happen
logger.error("Problem parsing id_token: " + e);
// e.printStackTrace();
throw new AuthenticationServiceException(
"Problem parsing id_token return from Token endpoint: " + e);
}
} else {
// An error is unlikely, but it good security to check
logger.error("Token Endpoint did not return a token_id");
throw new AuthenticationServiceException(
"Token Endpoint did not return a token_id");
}
// Handle Check ID Endpoint interaction
httpClient = new DefaultHttpClient();
httpClient.getParams().setParameter("http.socket.timeout",
new Integer(httpSocketTimeout));
factory = new HttpComponentsClientHttpRequestFactory(
httpClient);
restTemplate = new RestTemplate(factory);
form = new LinkedMultiValueMap<String, String>();
form.add("access_token",
jsonRoot.getAsJsonObject().get("id_token")
.getAsString());
jsonString = null;
try {
jsonString = restTemplate.postForObject(
checkIDEndpointURI, form, String.class);
} catch (HttpClientErrorException httpClientErrorException) {
// Handle error
logger.error("Check ID Endpoint error response: "
+ httpClientErrorException.getStatusText()
+ " : " + httpClientErrorException.getMessage());
throw new AuthenticationServiceException(
"Unable check token.");
}
jsonRoot = new JsonParser().parse(jsonString);
// String iss = jsonRoot.getAsJsonObject().get("iss")
// .getAsString();
String userId = jsonRoot.getAsJsonObject().get("user_id")
.getAsString();
// String aud = jsonRoot.getAsJsonObject().get("aud")
// .getAsString();
String nonce = jsonRoot.getAsJsonObject().get("nonce")
.getAsString();
// String exp = jsonRoot.getAsJsonObject().get("exp")
// .getAsString();
// Compare returned ID Token to signed session cookie
// to detect ID Token replay by third parties.
Cookie nonceSignatureCookie = WebUtils.getCookie(request,
NONCE_SIGNATURE_COOKIE_NAME);
if (nonceSignatureCookie != null) {
String sigText = nonceSignatureCookie.getValue();
if (sigText != null && !sigText.isEmpty()) {
if (!verify(signer, publicKey, nonce, sigText)) {
logger.error("Possible replay attack detected! "
+ "The comparison of the nonce in the returned "
+ "ID Token to the signed session "
+ NONCE_SIGNATURE_COOKIE_NAME
+ " failed.");
throw new AuthenticationServiceException(
"Possible replay attack detected! "
+ "The comparison of the nonce in the returned "
+ "ID Token to the signed session "
+ NONCE_SIGNATURE_COOKIE_NAME
+ " failed.");
}
} else {
logger.error(NONCE_SIGNATURE_COOKIE_NAME
+ " was found, but was null or empty.");
throw new AuthenticationServiceException(NONCE_SIGNATURE_COOKIE_NAME
+ " was found, but was null or empty.");
}
} else {
logger.error(NONCE_SIGNATURE_COOKIE_NAME
+ " cookie was not found.");
throw new AuthenticationServiceException(NONCE_SIGNATURE_COOKIE_NAME
+ " cookie was not found.");
}
// Create an Authentication object for the token, and
// return.
OpenIdConnectAuthenticationToken token = new OpenIdConnectAuthenticationToken(
userId, idToken);
Authentication authentication = this
.getAuthenticationManager().authenticate(token);
return authentication;
}
} else { } else {
// Initiate an Authorization request handleAuthorizationRequest(request, response);
Map<String, String> urlVariables = new HashMap<String, String>();
// Required parameters:
urlVariables.put("response_type", "code");
urlVariables.put("client_id", clientId);
urlVariables.put("scope", scope);
urlVariables.put("redirect_uri",
buildRedirectURI(request, null));
// Create a string value used to associate a user agent session
// with an ID Token to mitigate replay attacks. The value is
// passed through unmodified to the ID Token. One method is to
// store a random value as a signed session cookie, and pass the
// value in the nonce parameter.
String nonce = new BigInteger(50, new Random()).toString(16);
Cookie nonceCookie = new Cookie(NONCE_SIGNATURE_COOKIE_NAME,
sign(signer, privateKey, nonce.getBytes()));
response.addCookie(nonceCookie);
urlVariables.put("nonce", nonce);
// Optional parameters:
// TODO: display, prompt, request, request_uri
response.sendRedirect(buildURL(authorizationEndpointURI,
urlVariables));
} }
} }
@ -561,52 +348,305 @@ public class OpenIdConnectAuthenticationFilter extends
} }
/** /**
* Builds the redirect_uri that will be sent to the Authorization Endpoint. * Handles the authorization grant response
* By default returns the URL of the current request.
* *
* @param request * @param request
* the current request which is being processed by this filter * The request from which to extract parameters and perform the
* @param ingoreParameters * authentication
* an array of parameter names to ignore. * @return The authenticated user token, or null if authentication is
* @return * incomplete.
*/ */
private String buildRedirectURI(HttpServletRequest request, private Authentication handleAuthorizationGrantResponse(
String[] ingoreParameters) { HttpServletRequest request) {
List<String> ignore = (ingoreParameters != null) ? Arrays final boolean debug = logger.isDebugEnabled();
.asList(ingoreParameters) : null;
boolean isFirst = true; String authorizationGrant = request.getParameter("code");
StringBuffer sb = request.getRequestURL(); // Handle Token Endpoint interaction
HttpClient httpClient = new DefaultHttpClient();
for (Enumeration<?> e = request.getParameterNames(); e httpClient.getParams().setParameter("http.socket.timeout",
.hasMoreElements();) { new Integer(httpSocketTimeout));
String name = (String) e.nextElement(); //
// TODO: basic auth is untested (it wasn't working last I
// tested)
// UsernamePasswordCredentials credentials = new
// UsernamePasswordCredentials(
// clientId, clientSecret);
// ((DefaultHttpClient) httpClient).getCredentialsProvider()
// .setCredentials(AuthScope.ANY, credentials);
//
if ((ignore == null) || (!ignore.contains(name))) { HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(
// Assume for simplicity that there is only one value httpClient);
String value = request.getParameter(name);
if (value == null) { RestTemplate restTemplate = new RestTemplate(factory);
continue;
}
if (isFirst) { MultiValueMap<String, String> form = new LinkedMultiValueMap<String, String>();
sb.append("?"); form.add("grant_type", "authorization_code");
isFirst = false; form.add("code", authorizationGrant);
} form.add("redirect_uri", OpenIdConnectAuthenticationFilter
.buildRedirectURI(request, new String[] { "code" }));
sb.append(name).append("=").append(value); // pass clientId and clientSecret in post of request
form.add("client_id", clientId);
form.add("client_secret", clientSecret);
if (e.hasMoreElements()) { if (debug) {
sb.append("&"); logger.debug("tokenEndpointURI = " + tokenEndpointURI);
} logger.debug("form = " + form);
}
} }
return sb.toString(); String jsonString = null;
try {
jsonString = restTemplate.postForObject(tokenEndpointURI, form,
String.class);
} catch (HttpClientErrorException httpClientErrorException) {
// Handle error
logger.error("Token Endpoint error response: "
+ httpClientErrorException.getStatusText() + " : "
+ httpClientErrorException.getMessage());
throw new AuthenticationServiceException(
"Unable to obtain Access Token.");
}
JsonElement jsonRoot = new JsonParser().parse(jsonString);
if (jsonRoot.getAsJsonObject().get("error") != null) {
// Handle error
String error = jsonRoot.getAsJsonObject().get("error")
.getAsString();
logger.error("Token Endpoint returned: " + error);
throw new AuthenticationServiceException(
"Unable to obtain Access Token. Token Endpoint returned: "
+ error);
} else {
// Extract the id_token to insert into the
// OpenIdConnectAuthenticationToken
IdToken idToken = null;
if (jsonRoot.getAsJsonObject().get("id_token") != null) {
try {
idToken = IdToken.parse(jsonRoot.getAsJsonObject()
.get("id_token").getAsString());
} catch (Exception e) {
// I suspect this could happen
logger.error("Problem parsing id_token: " + e);
// e.printStackTrace();
throw new AuthenticationServiceException(
"Problem parsing id_token return from Token endpoint: "
+ e);
}
} else {
// An error is unlikely, but it good security to check
logger.error("Token Endpoint did not return a token_id");
throw new AuthenticationServiceException(
"Token Endpoint did not return a token_id");
}
// Handle Check ID Endpoint interaction
httpClient = new DefaultHttpClient();
httpClient.getParams().setParameter("http.socket.timeout",
new Integer(httpSocketTimeout));
factory = new HttpComponentsClientHttpRequestFactory(httpClient);
restTemplate = new RestTemplate(factory);
form = new LinkedMultiValueMap<String, String>();
form.add("access_token", jsonRoot.getAsJsonObject().get("id_token")
.getAsString());
jsonString = null;
try {
jsonString = restTemplate.postForObject(checkIDEndpointURI,
form, String.class);
} catch (HttpClientErrorException httpClientErrorException) {
// Handle error
logger.error("Check ID Endpoint error response: "
+ httpClientErrorException.getStatusText() + " : "
+ httpClientErrorException.getMessage());
throw new AuthenticationServiceException("Unable check token.");
}
jsonRoot = new JsonParser().parse(jsonString);
// String iss = jsonRoot.getAsJsonObject().get("iss")
// .getAsString();
String userId = jsonRoot.getAsJsonObject().get("user_id")
.getAsString();
// String aud = jsonRoot.getAsJsonObject().get("aud")
// .getAsString();
String nonce = jsonRoot.getAsJsonObject().get("nonce")
.getAsString();
// String exp = jsonRoot.getAsJsonObject().get("exp")
// .getAsString();
// Compare returned ID Token to signed session cookie
// to detect ID Token replay by third parties.
Cookie nonceSignatureCookie = WebUtils.getCookie(request,
NONCE_SIGNATURE_COOKIE_NAME);
if (nonceSignatureCookie != null) {
String sigText = nonceSignatureCookie.getValue();
if (sigText != null && !sigText.isEmpty()) {
if (!verify(signer, publicKey, nonce, sigText)) {
logger.error("Possible replay attack detected! "
+ "The comparison of the nonce in the returned "
+ "ID Token to the signed session "
+ NONCE_SIGNATURE_COOKIE_NAME + " failed.");
throw new AuthenticationServiceException(
"Possible replay attack detected! "
+ "The comparison of the nonce in the returned "
+ "ID Token to the signed session "
+ NONCE_SIGNATURE_COOKIE_NAME
+ " failed.");
}
} else {
logger.error(NONCE_SIGNATURE_COOKIE_NAME
+ " was found, but was null or empty.");
throw new AuthenticationServiceException(
NONCE_SIGNATURE_COOKIE_NAME
+ " was found, but was null or empty.");
}
} else {
logger.error(NONCE_SIGNATURE_COOKIE_NAME
+ " cookie was not found.");
throw new AuthenticationServiceException(
NONCE_SIGNATURE_COOKIE_NAME + " cookie was not found.");
}
// Create an Authentication object for the token, and
// return.
OpenIdConnectAuthenticationToken token = new OpenIdConnectAuthenticationToken(
userId, idToken);
Authentication authentication = this.getAuthenticationManager()
.authenticate(token);
return authentication;
}
}
/**
* Initiate an Authorization request
*
* @param request
* The request from which to extract parameters and perform the
* authentication
* @param response
* The response, needed to set a cookie and do a redirect as part
* of a multi-stage authentication process
* @throws IOException
* If an input or output exception occurs
*/
private void handleAuthorizationRequest(HttpServletRequest request,
HttpServletResponse response) throws IOException {
Map<String, String> urlVariables = new HashMap<String, String>();
// Required parameters:
urlVariables.put("response_type", "code");
urlVariables.put("client_id", clientId);
urlVariables.put("scope", scope);
urlVariables.put("redirect_uri", OpenIdConnectAuthenticationFilter
.buildRedirectURI(request, null));
// Create a string value used to associate a user agent session
// with an ID Token to mitigate replay attacks. The value is
// passed through unmodified to the ID Token. One method is to
// store a random value as a signed session cookie, and pass the
// value in the nonce parameter.
String nonce = new BigInteger(50, new SecureRandom()).toString(16);
Cookie nonceCookie = new Cookie(NONCE_SIGNATURE_COOKIE_NAME, sign(
signer, privateKey, nonce.getBytes()));
response.addCookie(nonceCookie);
urlVariables.put("nonce", nonce);
// Optional parameters:
// TODO: display, prompt, request, request_uri
response.sendRedirect(OpenIdConnectAuthenticationFilter.buildURL(
authorizationEndpointURI, urlVariables));
}
/**
* Handle Authorization Endpoint error
*
* @param request
* The request from which to extract parameters and handle the
* error
* @param response
* The response, needed to do a redirect to display the error
* @throws IOException
* If an input or output exception occurs
*/
private void handleError(HttpServletRequest request,
HttpServletResponse response) throws IOException {
String error = request.getParameter("error");
String errorDescription = request.getParameter("error_description");
String errorURI = request.getParameter("error_uri");
Map<String, String> requestParams = new HashMap<String, String>();
requestParams.put("error", error);
if (errorDescription != null) {
requestParams.put("error_description", errorDescription);
}
if (errorURI != null) {
requestParams.put("error_uri", errorURI);
}
response.sendRedirect(OpenIdConnectAuthenticationFilter.buildURL(
errorRedirectURI, requestParams));
} }
public void setAuthorizationEndpointURI(String authorizationEndpointURI) { public void setAuthorizationEndpointURI(String authorizationEndpointURI) {