From 3bf46413b1bc3b21e743e35ebf47fa6b4e285888 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Prante?= Date: Wed, 17 Apr 2024 16:26:06 +0200 Subject: [PATCH] smarter auth handling --- .../xbib/net/http/j2html/J2HtmlResource.java | 3 +- .../auth/BasicAuthenticationHandler.java | 4 +- .../auth/FormAuthenticationHandler.java | 13 +++-- .../auth/LoginAuthenticationHandler.java | 51 +++++++++++-------- .../server/resource/HtmlTemplateResource.java | 5 +- .../GroovyFormAuthenticationHandler.java | 14 ++--- 6 files changed, 56 insertions(+), 34 deletions(-) diff --git a/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlResource.java b/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlResource.java index 9b82ddd..8da9777 100644 --- a/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlResource.java +++ b/net-http-j2html/src/main/java/org/xbib/net/http/j2html/J2HtmlResource.java @@ -40,7 +40,8 @@ public class J2HtmlResource extends HtmlTemplateResource { .header("cache-control", cacheControl()) // override default must-revalidate behavior .header("content-length", Integer.toString(dataBuffer.writePosition())) .header(CONTENT_TYPE, "text/html; charset=" + getCharset().displayName()) - .body(dataBuffer); + .body(dataBuffer) + .done(); } protected String cacheControl() { diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/auth/BasicAuthenticationHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/auth/BasicAuthenticationHandler.java index dfeec2b..212df0b 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/auth/BasicAuthenticationHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/auth/BasicAuthenticationHandler.java @@ -39,7 +39,9 @@ public class BasicAuthenticationHandler extends LoginAuthenticationHandler imple } userProfile = new BaseUserProfile(); try { - authenticate(userProfile, tokens[0], tokens[1], httpRequest); + if (authenticate(userProfile, tokens[0], tokens[1], httpRequest)) { + context.setAuthenticated(true); + } context.getAttributes().put("userprofile", userProfile); return; } catch (Exception e) { diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/auth/FormAuthenticationHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/auth/FormAuthenticationHandler.java index e9177e2..8dcc0e9 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/auth/FormAuthenticationHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/auth/FormAuthenticationHandler.java @@ -23,9 +23,11 @@ public class FormAuthenticationHandler extends LoginAuthenticationHandler implem @Override public void handle(HttpRouterContext context) throws IOException { + logger.log(Level.FINE, "request = " + context.getRequest()); UserProfile userProfile = context.getAttributes().get(UserProfile.class, "userprofile"); if (userProfile != null && userProfile.getUserId() != null) { logger.log(Level.FINE, "user id already set: " + userProfile.getUserId()); + context.setAuthenticated(true); return; } if (context.isAuthenticated()) { @@ -34,29 +36,30 @@ public class FormAuthenticationHandler extends LoginAuthenticationHandler implem } // always add an "anonymous" user profile with a null user ID userProfile = new BaseUserProfile(); - context.getAttributes().put("userprofile", userProfile); boolean isAuthenticated = false; try { Parameter parameter = context.getRequest().getParameter(); if (!parameter.containsKey(getUserParameterName(), Parameter.Domain.FORM)) { - logger.log(Level.WARNING, "usernameParameter not set, unable to authenticate"); + logger.log(Level.WARNING, "username parameter not set, unable to authenticate"); prepareFormAuthentication(context); return; } String username = parameter.getAsString(getUserParameterName(), Parameter.Domain.FORM); if (!parameter.containsKey(getPasswordParameterName(), Parameter.Domain.FORM)) { - logger.log(Level.WARNING, "passwordParameter not set, unable to authenticate"); + logger.log(Level.WARNING, "password parameter not set, unable to authenticate"); prepareFormAuthentication(context); return; } String password = parameter.getAsString(getPasswordParameterName(), Parameter.Domain.FORM); - authenticate(userProfile, username, password, context.getRequest()); - isAuthenticated = true; + if (authenticate(userProfile, username, password, context.getRequest())) { + isAuthenticated = true; + } } catch (ParameterException e) { logger.log(Level.SEVERE, "parameter error"); } catch (Exception e) { logger.log(Level.SEVERE, "authentication error"); } finally { + context.getAttributes().put("userprofile", userProfile); context.setAuthenticated(isAuthenticated); if (!isAuthenticated) { prepareFormAuthentication(context); diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/auth/LoginAuthenticationHandler.java b/net-http-server/src/main/java/org/xbib/net/http/server/auth/LoginAuthenticationHandler.java index e6abb3f..56e5e86 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/auth/LoginAuthenticationHandler.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/auth/LoginAuthenticationHandler.java @@ -2,6 +2,7 @@ package org.xbib.net.http.server.auth; import java.io.IOException; import java.util.Collection; +import java.util.Objects; import java.util.logging.Level; import java.util.logging.Logger; import org.xbib.net.Authenticator; @@ -26,12 +27,12 @@ public class LoginAuthenticationHandler implements HttpHandler { private final SecurityRealm securityRealm; - public LoginAuthenticationHandler(String userParameterName, + public LoginAuthenticationHandler(String usernameParameterName, String passwordParameterName, SecurityRealm securityRealm) { - this.userParameterName = userParameterName; - this.passwordParameterName = passwordParameterName; - this.securityRealm = securityRealm; + this.userParameterName = Objects.requireNonNull(usernameParameterName, "username parameter must not be null"); + this.passwordParameterName = Objects.requireNonNull(passwordParameterName, "password parameter must not be null"); + this.securityRealm = Objects.requireNonNull(securityRealm, "security realm must not be null"); } public String getUserParameterName() { @@ -49,7 +50,12 @@ public class LoginAuthenticationHandler implements HttpHandler { @Override public void handle(HttpRouterContext context) throws IOException { UserProfile userProfile = context.getAttributes().get(UserProfile.class, "userprofile"); - if (userProfile != null && userProfile.getUserId() != null) { + if (userProfile == null) { + logger.log(Level.FINE, "no user profile found in context"); + return; + } + if (userProfile.getUserId() != null) { + logger.log(Level.FINE, "user id already set"); return; } Parameter parameter = context.getRequest().getParameter(); @@ -59,8 +65,9 @@ public class LoginAuthenticationHandler implements HttpHandler { try { String username = parameter.getAsString(getUserParameterName(), Parameter.Domain.FORM); String password = parameter.getAsString(getPasswordParameterName(), Parameter.Domain.FORM); - authenticate(userProfile, username, password, context.getRequest()); - isAuthenticated = true; + if (authenticate(userProfile, username, password, context.getRequest())) { + isAuthenticated = true; + } } catch (ParameterException e) { logger.log(Level.SEVERE, "parameter error"); } catch (Exception e) { @@ -70,29 +77,33 @@ public class LoginAuthenticationHandler implements HttpHandler { } } - protected void authenticate(UserProfile userProfile, String username, String password, Request request) { + protected boolean authenticate(UserProfile userProfile, String username, String password, Request request) { if (username == null) { logger.log(Level.FINE, "no username given for check, doing nothing"); - return; + return false; } if (password == null) { logger.log(Level.FINE, "no password given for check, doing nothing"); - return; + return false; } Authenticator auth = securityRealm.getAuthenticator(); Authenticator.Context authContext = new Authenticator.Context(username, password, request); if (auth.authenticate(authContext)) { + logger.log(Level.FINE, "authenticated, augmenting user profile with " + authContext.getUsername()); userProfile.setUserId(authContext.getUsername()); + UsersProvider.Context userContext = new UsersProvider.Context(username, null); + UserDetails userDetails = securityRealm.getUsersProvider().getUserDetails(userContext); + userProfile.setEffectiveUserId(userDetails.getEffectiveUserId()); + userProfile.setName(userDetails.getName()); + GroupsProvider.Context groupContext = new GroupsProvider.Context(username, null); + Collection groups = securityRealm.getGroupsProvider().getGroups(groupContext); + for (String group : groups) { + userProfile.addRole(group); + } + logger.log(Level.FINE, "authentication success: userProfile = " + userProfile); + return true; } - UsersProvider.Context userContext = new UsersProvider.Context(username, null); - UserDetails userDetails = securityRealm.getUsersProvider().getUserDetails(userContext); - userProfile.setEffectiveUserId(userDetails.getEffectiveUserId()); - userProfile.setName(userDetails.getName()); - GroupsProvider.Context groupContext = new GroupsProvider.Context(username, null); - Collection groups = securityRealm.getGroupsProvider().getGroups(groupContext); - for (String group : groups) { - userProfile.addRole(group); - } - logger.log(Level.FINE, "authenticate: userProfile = " + userProfile); + logger.log(Level.FINE, "authentication failure"); + return false; } } diff --git a/net-http-server/src/main/java/org/xbib/net/http/server/resource/HtmlTemplateResource.java b/net-http-server/src/main/java/org/xbib/net/http/server/resource/HtmlTemplateResource.java index a6ccc23..c084d0a 100644 --- a/net-http-server/src/main/java/org/xbib/net/http/server/resource/HtmlTemplateResource.java +++ b/net-http-server/src/main/java/org/xbib/net/http/server/resource/HtmlTemplateResource.java @@ -233,6 +233,9 @@ public class HtmlTemplateResource implements HttpServerResource { private static String toOrigin(URL url) { StringBuilder sb = new StringBuilder(); + if (url == null) { + return sb.toString(); + } if (url.getPath() != null) { sb.append(url.getPath()); } @@ -242,7 +245,7 @@ public class HtmlTemplateResource implements HttpServerResource { if (url.getFragment() != null) { sb.append('#').append(url.getFragment()); } - if (sb.length() == 0) { + if (sb.isEmpty()) { sb.append('/'); } return sb.toString(); diff --git a/net-http-template-groovy/src/main/java/org/xbib/net/http/template/groovy/GroovyFormAuthenticationHandler.java b/net-http-template-groovy/src/main/java/org/xbib/net/http/template/groovy/GroovyFormAuthenticationHandler.java index 470f9e9..b90427e 100644 --- a/net-http-template-groovy/src/main/java/org/xbib/net/http/template/groovy/GroovyFormAuthenticationHandler.java +++ b/net-http-template-groovy/src/main/java/org/xbib/net/http/template/groovy/GroovyFormAuthenticationHandler.java @@ -53,9 +53,11 @@ public class GroovyFormAuthenticationHandler extends FormAuthenticationHandler { String username = parameter.getAsString(getUserParameterName(), Parameter.Domain.FORM); String password = parameter.getAsString(getPasswordParameterName(), Parameter.Domain.FORM); logger.log(Level.FINE, "username and password found, ready for authentication"); - authenticate(userProfile, username, password, context.getRequest()); - logger.log(Level.FINE, "successful authentication"); - return; + if (authenticate(userProfile, username, password, context.getRequest())) { + context.setAuthenticated(true); + logger.log(Level.FINE, "successful authentication"); + return; + } } catch (ParameterException e) { logger.log(Level.SEVERE, "parameter error"); } catch (Exception e) { @@ -70,8 +72,8 @@ public class GroovyFormAuthenticationHandler extends FormAuthenticationHandler { // We need a full path resolve against the server URL. logger.log(Level.FINE, "set new templatePath, login template = " + loginTemplate); context.getAttributes().put("templatePath", loginTemplate); - URL loc = context.getContextURL().resolve(context.getRequest().getRequestURI()).normalize(); - logger.log(Level.FINE, "context URL = " + context.getContextURL() + " request URI = " + context.getRequest().getRequestURI() + " loc = " + loc); - context.getAttributes().put("originalPath", loc.toExternalForm()); + URL origin = context.getContextURL().resolve(context.getRequest().getRequestURI()).normalize(); + logger.log(Level.FINE, "context URL = " + context.getContextURL() + " request URI = " + context.getRequest().getRequestURI() + " origin = " + origin); + context.getAttributes().put("originalPath", origin.toExternalForm()); } }