From 8bbb651169713c4e2cbc96a00384fe4667037b40 Mon Sep 17 00:00:00 2001 From: Ziver Koc Date: Fri, 27 Nov 2020 01:59:35 +0100 Subject: [PATCH] Added some more logging to OAuth2 and a token listener --- .../page/oauth/OAuth2AuthorizationPage.java | 27 +++++++++-------- .../net/http/page/oauth/OAuth2Registry.java | 23 ++++++++++++++ .../net/http/page/oauth/OAuth2TokenPage.java | 30 ++++++++----------- 3 files changed, 51 insertions(+), 29 deletions(-) diff --git a/src/zutil/net/http/page/oauth/OAuth2AuthorizationPage.java b/src/zutil/net/http/page/oauth/OAuth2AuthorizationPage.java index deceee0..28b1eff 100644 --- a/src/zutil/net/http/page/oauth/OAuth2AuthorizationPage.java +++ b/src/zutil/net/http/page/oauth/OAuth2AuthorizationPage.java @@ -100,34 +100,34 @@ public class OAuth2AuthorizationPage implements HttpPage { // Validate parameters // ----------------------------------------------- + HttpURL url = null; + String clientId = request.get("client_id"); + // Validate redirect_uri if (!request.containsKey("redirect_uri")) { - errorResponse(out, "Bad Request, missing parameter: redirect_uri"); + errorResponse(out, clientId, "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")); + errorResponse(out, clientId, "Invalid redirect URL: " + request.get("redirect_uri")); return; } // Validate client_id if (!request.containsKey("client_id")) { - errorResponse(out, "Bad Request, missing parameter: client_id"); + errorResponse(out, clientId, "Bad Request, missing parameter: client_id"); return; } - String clientId = request.get("client_id"); - if (!registry.isClientIdValid(clientId)) { - errorRedirect(out, url, ERROR_UNAUTHORIZED_CLIENT, request.get("state"), + errorRedirect(out, clientId, url, ERROR_UNAUTHORIZED_CLIENT, request.get("state"), "Bad Request, invalid client_id value."); return; } @@ -135,7 +135,7 @@ public class OAuth2AuthorizationPage implements HttpPage { // Validate response_type if (!request.containsKey("response_type")) { - errorRedirect(out, url, ERROR_INVALID_REQUEST, request.get("state"), + errorRedirect(out, clientId, url, ERROR_INVALID_REQUEST, request.get("state"), "Missing parameter response_type."); return; } @@ -156,13 +156,14 @@ public class OAuth2AuthorizationPage implements HttpPage { case RESPONSE_TYPE_PASSWORD: case RESPONSE_TYPE_CREDENTIALS: default: - errorRedirect(out, url, ERROR_INVALID_REQUEST, request.get("state"), + errorRedirect(out, clientId, url, ERROR_INVALID_REQUEST, request.get("state"), "unsupported response_type: " + request.get("response_type")); return; } // Setup the redirect + logger.warning("OAuth2 successful authorization of client: " + clientId); redirect(out, url); } @@ -170,7 +171,9 @@ public class OAuth2AuthorizationPage implements HttpPage { // Error handling // ------------------------------------------------------ - private static void errorResponse(HttpPrintStream out, String description) { + private static void errorResponse(HttpPrintStream out, String clientId, String description) { + logger.warning("OAuth2 Client" + (clientId!=null ? "(" + clientId + ")" : "") + " Authorization Error: " + description); + out.setResponseStatusCode(400); out.println(description); } @@ -184,8 +187,8 @@ public class OAuth2AuthorizationPage implements HttpPage { * @param state * @param description */ - private static void errorRedirect(HttpPrintStream out, HttpURL url, String error, String state, String description) { - logger.warning("OAuth2 Authorization Error(" + error + "): " + description); + private static void errorRedirect(HttpPrintStream out, String clientId, HttpURL url, String error, String state, String description) { + logger.warning("OAuth2 Client" + (clientId!=null ? "(" + clientId + ")" : "") + " Authorization Error: " + error + " = " + description); out.setHeader(HttpHeader.HEADER_CONTENT_TYPE, "application/x-www-form-urlencoded"); url.setParameter("error", error); diff --git a/src/zutil/net/http/page/oauth/OAuth2Registry.java b/src/zutil/net/http/page/oauth/OAuth2Registry.java index e7bfd66..06796b4 100644 --- a/src/zutil/net/http/page/oauth/OAuth2Registry.java +++ b/src/zutil/net/http/page/oauth/OAuth2Registry.java @@ -44,6 +44,7 @@ public class OAuth2Registry implements Serializable { private boolean requireWhitelist = true; transient private Random random = new Random(); + transient private TokenRegistrationListener tokenListener; // ------------------------------------------------------ @@ -161,6 +162,9 @@ public class OAuth2Registry implements Serializable { if (reg != null) { reg.accessTokens.put(token, new Timer(timeoutMillis).start()); + + if (tokenListener != null) + tokenListener.onTokenRegistration(clientId, token, timeoutMillis); return timeoutMillis; } return -1; @@ -204,6 +208,25 @@ public class OAuth2Registry implements Serializable { return null; } + // ------------------------------------------------------ + // Listeners + // ------------------------------------------------------ + + public void setTokenListener(TokenRegistrationListener listener) { + this.tokenListener = listener; + } + + public interface TokenRegistrationListener { + /** + * Method will be called when a new token is successfully registered on a client + * + * @param clientId the client ID that got the specified token + * @param token a String token that has ben generated and provided to the client + * @param timeoutMillis the expiration time of the token + */ + void onTokenRegistration(String clientId, String token, long timeoutMillis); + } + // ------------------------------------------------------ private ClientRegister getClientRegister(String clientId) { diff --git a/src/zutil/net/http/page/oauth/OAuth2TokenPage.java b/src/zutil/net/http/page/oauth/OAuth2TokenPage.java index 8eaba61..b5390d9 100644 --- a/src/zutil/net/http/page/oauth/OAuth2TokenPage.java +++ b/src/zutil/net/http/page/oauth/OAuth2TokenPage.java @@ -102,15 +102,14 @@ public class OAuth2TokenPage extends HttpJsonPage { // ----------------------------------------------- DataNode jsonRes = new DataNode(DataNode.DataType.Map); - - // Validate grant_type - String grantType = request.get("grant_type"); String codeKey; String clientId = null; + // Validate grant_type + if (grantType == null) - return errorResponse(out, ERROR_INVALID_REQUEST , request.get("state"), "Missing mandatory parameter grant_type."); + return errorResponse(out, clientId, ERROR_INVALID_REQUEST , request.get("state"), "Missing mandatory parameter grant_type."); switch (grantType) { case "authorization_code": @@ -121,15 +120,15 @@ public class OAuth2TokenPage extends HttpJsonPage { clientId = request.get("client_id"); if (clientId == null) - return errorResponse(out, ERROR_INVALID_REQUEST , request.get("state"), "Missing mandatory parameter: client_id"); + return errorResponse(out, clientId, ERROR_INVALID_REQUEST , request.get("state"), "Missing mandatory parameter: client_id"); if (!registry.isClientIdValid(clientId)) - return errorResponse(out, ERROR_INVALID_CLIENT , request.get("state"), "Invalid client_id value."); + return errorResponse(out, clientId, ERROR_INVALID_CLIENT , request.get("state"), "Invalid client_id value."); // Validate redirect_uri if (!request.containsKey("redirect_uri")) - return errorResponse(out, ERROR_INVALID_REQUEST , request.get("state"), "Missing mandatory parameter: redirect_uri"); + return errorResponse(out, clientId, ERROR_INVALID_REQUEST , request.get("state"), "Missing mandatory parameter: redirect_uri"); // TODO: ensure that the "redirect_uri" parameter is present if the // "redirect_uri" parameter was included in the initial authorization @@ -143,7 +142,7 @@ public class OAuth2TokenPage extends HttpJsonPage { break; default: - return errorResponse(out, ERROR_UNSUPPORTED_GRANT_TYPE, request.get("state"), "Unsupported grant_type: " + request.containsKey("grant_type")); + return errorResponse(out, clientId, ERROR_UNSUPPORTED_GRANT_TYPE, request.get("state"), "Unsupported grant_type: " + request.containsKey("grant_type")); } // Validate code and refresh_token @@ -151,10 +150,10 @@ public class OAuth2TokenPage extends HttpJsonPage { String authorizationCode = request.get(codeKey); if (authorizationCode == null) - return errorResponse(out, ERROR_INVALID_REQUEST , request.get("state"), "Missing mandatory parameter: " + codeKey); + return errorResponse(out, clientId, ERROR_INVALID_REQUEST , request.get("state"), "Missing mandatory parameter: " + codeKey); if (!registry.isAuthorizationCodeValid(authorizationCode)) - return errorResponse(out, ERROR_INVALID_GRANT, request.get("state"), "Invalid " + codeKey + " value."); + return errorResponse(out, clientId, ERROR_INVALID_GRANT, request.get("state"), "Invalid " + codeKey + " value."); // ----------------------------------------------- // Handle request @@ -163,6 +162,8 @@ public class OAuth2TokenPage extends HttpJsonPage { if (clientId == null) clientId = registry.getClientIdForAuthenticationCode(authorizationCode); + logger.warning("OAuth2 successful token provisioning for client: " + clientId); + String token = registry.generateToken(); long timeoutMillis = registry.registerAccessToken(clientId, token); @@ -182,7 +183,6 @@ public class OAuth2TokenPage extends HttpJsonPage { } - // ------------------------------------------------------ // Error handling // ------------------------------------------------------ @@ -190,14 +190,10 @@ public class OAuth2TokenPage extends HttpJsonPage { /** * @see RFC 6749: Chapter 5.2 * - * @param out - * @param error - * @param state - * @param description * @return A DataNode containing the error response */ - private static DataNode errorResponse(HttpPrintStream out, String error, String state, String description) { - logger.warning("OAuth2 Token Error(" + error + ") for client: " + description); + private static DataNode errorResponse(HttpPrintStream out, String clientId, String error, String state, String description) { + logger.warning("OAuth2 Client" + (clientId!=null ? "(" + clientId + ")" : "") + " Token Error: " + error + " = " + description); out.setResponseStatusCode(400);