Added test case for authorization page
This commit is contained in:
parent
8af91a9169
commit
f65cb0e4c4
6 changed files with 233 additions and 20 deletions
|
|
@ -62,6 +62,7 @@ public class HttpURL {
|
||||||
this.setHost(url.getHost());
|
this.setHost(url.getHost());
|
||||||
this.setPort(url.getPort());
|
this.setPort(url.getPort());
|
||||||
this.setPath(url.getPath());
|
this.setPath(url.getPath());
|
||||||
|
this.setParameters(url.getQuery());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -115,6 +116,16 @@ public class HttpURL {
|
||||||
this.parameters = pars;
|
this.parameters = pars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void setParameters(String query) {
|
||||||
|
if (query == null)
|
||||||
|
return;
|
||||||
|
HttpHeaderParser.parseURLParameters(parameters, query);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getParameter(String key) {
|
||||||
|
return parameters.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the parameter string in a URL.
|
* Generates the parameter string in a URL.
|
||||||
* <p>
|
* <p>
|
||||||
|
|
|
||||||
|
|
@ -80,23 +80,23 @@ public class OAuth2AuthorizationPage implements HttpPage {
|
||||||
|
|
||||||
/** The request is missing a required parameter, includes an invalid parameter value, includes a parameter
|
/** The request is missing a required parameter, includes an invalid parameter value, includes a parameter
|
||||||
more than once, or is otherwise malformed. **/
|
more than once, or is otherwise malformed. **/
|
||||||
protected static final String ERROR_INVALID_REQUEST = "invalid_request";
|
private static final String ERROR_INVALID_REQUEST = "invalid_request";
|
||||||
/** The client is not authorized to request an authorization code using this method. **/
|
/** The client is not authorized to request an authorization code using this method. **/
|
||||||
protected static final String ERROR_UNAUTHORIZED_CLIENT = "unauthorized_client";
|
private static final String ERROR_UNAUTHORIZED_CLIENT = "unauthorized_client";
|
||||||
/** The resource owner or authorization server denied the request. **/
|
/** The resource owner or authorization server denied the request. **/
|
||||||
protected static final String ERROR_ACCESS_DENIED = "access_denied";
|
private static final String ERROR_ACCESS_DENIED = "access_denied";
|
||||||
/** The authorization server does not support obtaining an authorization code using this method. **/
|
/** The authorization server does not support obtaining an authorization code using this method. **/
|
||||||
protected static final String ERROR_UNSUPPORTED_RESP_TYPE = "unsupported_response_type";
|
private static final String ERROR_UNSUPPORTED_RESP_TYPE = "unsupported_response_type";
|
||||||
/** The requested scope is invalid, unknown, or malformed. **/
|
/** The requested scope is invalid, unknown, or malformed. **/
|
||||||
protected static final String ERROR_INVALID_SCOPE = "invalid_scope";
|
private static final String ERROR_INVALID_SCOPE = "invalid_scope";
|
||||||
/** The authorization server encountered an unexpected condition that prevented it from fulfilling the request.
|
/** The authorization server encountered an unexpected condition that prevented it from fulfilling the request.
|
||||||
(This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client
|
(This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client
|
||||||
via an HTTP redirect.) **/
|
via an HTTP redirect.) **/
|
||||||
protected static final String ERROR_SERVER_ERROR = "server_error";
|
private static final String ERROR_SERVER_ERROR = "server_error";
|
||||||
/** The authorization server is currently unable to handle the request due to a temporary overloading or maintenance
|
/** The authorization server is currently unable to handle the request due to a temporary overloading or maintenance
|
||||||
of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned
|
of the server. (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned
|
||||||
to the client via an HTTP redirect.) **/
|
to the client via an HTTP redirect.) **/
|
||||||
protected static final String ERROR_TEMPORARILY_UNAVAILABLE = "temporarily_unavailable";
|
private static final String ERROR_TEMPORARILY_UNAVAILABLE = "temporarily_unavailable";
|
||||||
|
|
||||||
private static final String RESPONSE_TYPE_CODE = "code";
|
private static final String RESPONSE_TYPE_CODE = "code";
|
||||||
private static final String RESPONSE_TYPE_PASSWORD = "password";
|
private static final String RESPONSE_TYPE_PASSWORD = "password";
|
||||||
|
|
@ -117,34 +117,64 @@ public class OAuth2AuthorizationPage implements HttpPage {
|
||||||
HttpHeader headers,
|
HttpHeader headers,
|
||||||
Map<String, Object> session,
|
Map<String, Object> session,
|
||||||
Map<String, String> cookie,
|
Map<String, String> cookie,
|
||||||
Map<String, String> request) throws MalformedURLException {
|
Map<String, String> request) {
|
||||||
|
|
||||||
|
// -----------------------------------------------
|
||||||
|
// Validate parameters
|
||||||
|
// -----------------------------------------------
|
||||||
|
|
||||||
|
// Validate redirect_uri
|
||||||
|
|
||||||
if (!request.containsKey("redirect_uri")) {
|
if (!request.containsKey("redirect_uri")) {
|
||||||
errorResponse(out, "Bad Request, missing property: redirect_uri");
|
errorResponse(out, "Bad Request, missing parameter: redirect_uri");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpURL url = null;
|
||||||
|
try {
|
||||||
|
url = new HttpURL(URLDecoder.decode(request.get("redirect_uri")));
|
||||||
|
} catch(Exception e) {}
|
||||||
|
|
||||||
|
if (url == null || !"HTTPS".equalsIgnoreCase(url.getProtocol())) {
|
||||||
|
errorResponse(out, "Invalid redirect URL: " + request.get("redirect_uri"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate client_id
|
||||||
|
|
||||||
|
if (!request.containsKey("client_id")) {
|
||||||
|
errorResponse(out, "Bad Request, missing parameter: client_id");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String clientId = request.get("client_id");
|
String clientId = request.get("client_id");
|
||||||
|
|
||||||
if (registry.isClientIdValid(clientId)) {
|
if (!registry.isClientIdValid(clientId)) {
|
||||||
errorResponse(out, "Bad Request, missing or invalid client_id value.");
|
errorRedirect(out, url, ERROR_UNAUTHORIZED_CLIENT, request.get("state"),
|
||||||
|
"Bad Request, invalid client_id value.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpURL url = new HttpURL(URLDecoder.decode(request.get("redirect_uri")));
|
// Validate response_type
|
||||||
|
|
||||||
if (!"HTTPS".equalsIgnoreCase(url.getProtocol())) {
|
if (!request.containsKey("response_type")) {
|
||||||
errorResponse(out, "Bad redirect protocol: " + url.getProtocol());
|
errorRedirect(out, url, ERROR_INVALID_REQUEST, request.get("state"),
|
||||||
|
"Missing parameter response_type.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// -----------------------------------------------
|
||||||
|
// Handle request
|
||||||
|
// -----------------------------------------------
|
||||||
|
|
||||||
switch (request.get("response_type")) {
|
switch (request.get("response_type")) {
|
||||||
case RESPONSE_TYPE_CODE:
|
case RESPONSE_TYPE_CODE:
|
||||||
String code = generateCode();
|
String code = generateCode();
|
||||||
registry.registerAuthorizationCode(clientId, code);
|
registry.registerAuthorizationCode(clientId, code);
|
||||||
|
|
||||||
url.setParameter("state", request.get("state"));
|
|
||||||
url.setParameter("code", code);
|
url.setParameter("code", code);
|
||||||
|
if (request.containsKey("state"))
|
||||||
|
url.setParameter("state", request.get("state"));
|
||||||
break;
|
break;
|
||||||
case RESPONSE_TYPE_PASSWORD:
|
case RESPONSE_TYPE_PASSWORD:
|
||||||
case RESPONSE_TYPE_CREDENTIALS:
|
case RESPONSE_TYPE_CREDENTIALS:
|
||||||
|
|
@ -160,7 +190,7 @@ public class OAuth2AuthorizationPage implements HttpPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String generateCode() {
|
private String generateCode() {
|
||||||
return String.valueOf(random.nextInt());
|
return String.valueOf(Math.abs(random.nextLong()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ public class OAuth2Registry {
|
||||||
private static final long DEFAULT_TIMEOUT = 24 * 60 * 60 * 1000; // 24h
|
private static final long DEFAULT_TIMEOUT = 24 * 60 * 60 * 1000; // 24h
|
||||||
|
|
||||||
private Map<String, ClientRegister> clientRegistry = new HashMap<>();
|
private Map<String, ClientRegister> clientRegistry = new HashMap<>();
|
||||||
private boolean requireWhitelist = false;
|
private boolean requireWhitelist = true;
|
||||||
|
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
|
|
@ -71,7 +71,7 @@ public class OAuth2Registry {
|
||||||
/**
|
/**
|
||||||
* Set the requirement or non-requirement of pre-registered client-ids.
|
* Set the requirement or non-requirement of pre-registered client-ids.
|
||||||
* If enabled then any clients starting a OAuth2 process needs to have a
|
* If enabled then any clients starting a OAuth2 process needs to have a
|
||||||
* preregistered client-id value in the registry object.
|
* preregistered client-id value in the registry object. (Default is set to true)
|
||||||
*
|
*
|
||||||
* @param enabled if true then all requests will be required to be in whitelist
|
* @param enabled if true then all requests will be required to be in whitelist
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,7 @@ public class OAuth2TokenPage extends HttpJsonPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String generateToken() {
|
private String generateToken() {
|
||||||
return String.valueOf(random.nextInt());
|
return String.valueOf(Math.abs(random.nextLong()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ public class HttpTestUtil {
|
||||||
StringOutputStream buff = new StringOutputStream();
|
StringOutputStream buff = new StringOutputStream();
|
||||||
HttpPrintStream out = new HttpPrintStream(buff);
|
HttpPrintStream out = new HttpPrintStream(buff);
|
||||||
|
|
||||||
page.respond(out, headers, session, new HashMap(), new HashMap());
|
page.respond(out, headers, session, new HashMap(), headers.getURLAttributeMap());
|
||||||
|
|
||||||
out.flush();
|
out.flush();
|
||||||
HttpHeaderParser parser = new HttpHeaderParser(buff.toString());
|
HttpHeaderParser parser = new HttpHeaderParser(buff.toString());
|
||||||
|
|
|
||||||
172
test/zutil/net/http/page/oauth/OAuth2TokenPageTest.java
Normal file
172
test/zutil/net/http/page/oauth/OAuth2TokenPageTest.java
Normal file
|
|
@ -0,0 +1,172 @@
|
||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 Ziver Koc
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package zutil.net.http.page.oauth;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import zutil.net.http.HttpHeader;
|
||||||
|
import zutil.net.http.HttpTestUtil;
|
||||||
|
import zutil.net.http.HttpURL;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class OAuth2TokenPageTest {
|
||||||
|
|
||||||
|
private OAuth2Registry registry;
|
||||||
|
private OAuth2AuthorizationPage authPage;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init(){
|
||||||
|
registry = new OAuth2Registry();
|
||||||
|
authPage = new OAuth2AuthorizationPage(registry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void invalidRedirect() throws IOException {
|
||||||
|
registry.addWhitelist("12345");
|
||||||
|
HttpHeader reqHeader = new HttpHeader();
|
||||||
|
HttpHeader rspHeader = HttpTestUtil.makeRequest(authPage, reqHeader);
|
||||||
|
|
||||||
|
// redirect_uri and client_id not provided
|
||||||
|
|
||||||
|
assertEquals(400, rspHeader.getResponseStatusCode());
|
||||||
|
assertNull(rspHeader.getHeader("Location"));
|
||||||
|
|
||||||
|
// redirect_uri not provided
|
||||||
|
|
||||||
|
reqHeader.setURLAttribute("client_id", "12345");
|
||||||
|
rspHeader = HttpTestUtil.makeRequest(authPage, reqHeader);
|
||||||
|
|
||||||
|
assertEquals(400, rspHeader.getResponseStatusCode());
|
||||||
|
assertNull(rspHeader.getHeader("Location"));
|
||||||
|
|
||||||
|
// redirect_uri is not a valid URL
|
||||||
|
|
||||||
|
reqHeader.setURLAttribute("redirect_uri", "incorrect url");
|
||||||
|
rspHeader = HttpTestUtil.makeRequest(authPage, reqHeader);
|
||||||
|
|
||||||
|
assertEquals(400, rspHeader.getResponseStatusCode());
|
||||||
|
assertNull(rspHeader.getHeader("Location"));
|
||||||
|
|
||||||
|
// redirect_uri is not HTTPS
|
||||||
|
|
||||||
|
reqHeader.setURLAttribute("redirect_uri", "http://example.com");
|
||||||
|
rspHeader = HttpTestUtil.makeRequest(authPage, reqHeader);
|
||||||
|
|
||||||
|
assertEquals(400, rspHeader.getResponseStatusCode());
|
||||||
|
assertNull(rspHeader.getHeader("Location"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void invalidClientId() throws IOException {
|
||||||
|
HttpHeader reqHeader = new HttpHeader();
|
||||||
|
reqHeader.setURLAttribute("redirect_uri", "https://example.com");
|
||||||
|
HttpHeader rspHeader = HttpTestUtil.makeRequest(authPage, reqHeader);
|
||||||
|
|
||||||
|
// client_id not provided
|
||||||
|
|
||||||
|
assertEquals(400, rspHeader.getResponseStatusCode());
|
||||||
|
assertNull(rspHeader.getHeader("Location"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The request is missing a required parameter, includes an invalid parameter value, includes a parameter
|
||||||
|
more than once, or is otherwise malformed. **/
|
||||||
|
@Test
|
||||||
|
public void errorInvalidRequest() throws IOException {
|
||||||
|
registry.addWhitelist("12345");
|
||||||
|
HttpHeader reqHeader = new HttpHeader();
|
||||||
|
reqHeader.setURLAttribute("client_id", "12345");
|
||||||
|
reqHeader.setURLAttribute("redirect_uri", "https://example.com");
|
||||||
|
HttpHeader rspHeader = HttpTestUtil.makeRequest(authPage, reqHeader);
|
||||||
|
|
||||||
|
// Missing response_type
|
||||||
|
|
||||||
|
assertEquals(302, rspHeader.getResponseStatusCode());
|
||||||
|
HttpURL url = new HttpURL(rspHeader.getHeader("Location"));
|
||||||
|
assertNull(url.getParameter("code"));
|
||||||
|
assertEquals("invalid_request", url.getParameter("error"));
|
||||||
|
|
||||||
|
// response_type is not code
|
||||||
|
|
||||||
|
reqHeader.setURLAttribute("response_type", "not_code");
|
||||||
|
rspHeader = HttpTestUtil.makeRequest(authPage, reqHeader);
|
||||||
|
|
||||||
|
assertEquals(302, rspHeader.getResponseStatusCode());
|
||||||
|
assertNull(url.getParameter("code"));
|
||||||
|
assertEquals("invalid_request", url.getParameter("error"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The client is not authorized to request an authorization code using this method. **/
|
||||||
|
@Test
|
||||||
|
public void errorUnauthorizedClient() throws IOException {
|
||||||
|
registry.addWhitelist("12345");
|
||||||
|
HttpHeader reqHeader = new HttpHeader();
|
||||||
|
reqHeader.setURLAttribute("client_id", "67890");
|
||||||
|
reqHeader.setURLAttribute("redirect_uri", "https://example.com");
|
||||||
|
HttpHeader rspHeader = HttpTestUtil.makeRequest(authPage, reqHeader);
|
||||||
|
|
||||||
|
// Missing response_type
|
||||||
|
|
||||||
|
assertEquals(302, rspHeader.getResponseStatusCode());
|
||||||
|
HttpURL url = new HttpURL(rspHeader.getHeader("Location"));
|
||||||
|
assertNull(url.getParameter("code"));
|
||||||
|
assertEquals("unauthorized_client", url.getParameter("error"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void requestBasic() throws IOException {
|
||||||
|
registry.addWhitelist("12345");
|
||||||
|
HttpHeader reqHeader = new HttpHeader();
|
||||||
|
reqHeader.setURLAttribute("client_id", "12345");
|
||||||
|
reqHeader.setURLAttribute("redirect_uri", "https://example.com");
|
||||||
|
reqHeader.setURLAttribute("response_type", "code");
|
||||||
|
HttpHeader rspHeader = HttpTestUtil.makeRequest(authPage, reqHeader);
|
||||||
|
|
||||||
|
assertEquals(302, rspHeader.getResponseStatusCode());
|
||||||
|
HttpURL url = new HttpURL(rspHeader.getHeader("Location"));
|
||||||
|
assertEquals("example.com", url.getHost());
|
||||||
|
assertNotNull(url.getParameter("code"));
|
||||||
|
assertNull(url.getParameter("state"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void requestWithState() throws IOException {
|
||||||
|
registry.addWhitelist("12345");
|
||||||
|
HttpHeader reqHeader = new HttpHeader();
|
||||||
|
reqHeader.setURLAttribute("client_id", "12345");
|
||||||
|
reqHeader.setURLAttribute("redirect_uri", "https://example.com");
|
||||||
|
reqHeader.setURLAttribute("response_type", "code");
|
||||||
|
reqHeader.setURLAttribute("state", "app_state");
|
||||||
|
HttpHeader rspHeader = HttpTestUtil.makeRequest(authPage, reqHeader);
|
||||||
|
|
||||||
|
assertEquals(302, rspHeader.getResponseStatusCode());
|
||||||
|
HttpURL url = new HttpURL(rspHeader.getHeader("Location"));
|
||||||
|
assertEquals("app_state", url.getParameter("state"));
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue