add security context related j2html resources
This commit is contained in:
parent
6e83937cc1
commit
c56634b281
21 changed files with 336 additions and 133 deletions
|
@ -1,3 +1,3 @@
|
||||||
group = org.xbib
|
group = org.xbib
|
||||||
name = net-http
|
name = net-http
|
||||||
version = 4.4.3
|
version = 4.4.4
|
||||||
|
|
|
@ -13,7 +13,7 @@ module org.xbib.net.http.client.netty.secure.test {
|
||||||
requires org.xbib.net.http;
|
requires org.xbib.net.http;
|
||||||
requires org.xbib.net.http.client;
|
requires org.xbib.net.http.client;
|
||||||
requires org.xbib.net.http.client.netty;
|
requires org.xbib.net.http.client.netty;
|
||||||
requires org.xbib.net.http.client.netty.secure;
|
requires transitive org.xbib.net.http.client.netty.secure;
|
||||||
requires io.netty.handler.proxy;
|
requires io.netty.handler.proxy;
|
||||||
exports org.xbib.net.http.client.netty.secure.test;
|
exports org.xbib.net.http.client.netty.secure.test;
|
||||||
opens org.xbib.net.http.client.netty.secure.test;
|
opens org.xbib.net.http.client.netty.secure.test;
|
||||||
|
|
|
@ -17,10 +17,12 @@ public class Https2Test {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(Https2Test.class.getName());
|
private static final Logger logger = Logger.getLogger(Https2Test.class.getName());
|
||||||
|
|
||||||
@Disabled
|
public Https2Test() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Disabled("the xbib server does not offer HTTP/2 so this does not work!")
|
||||||
@Test
|
@Test
|
||||||
void testXbib() throws Exception {
|
void testXbib() throws Exception {
|
||||||
// the xbib server does not offer HTTP/2 so this does not work!
|
|
||||||
NettyHttpClientConfig config = new NettyHttpsClientConfig()
|
NettyHttpClientConfig config = new NettyHttpsClientConfig()
|
||||||
.setDebug(true);
|
.setDebug(true);
|
||||||
try (NettyHttpClient client = NettyHttpClient.builder()
|
try (NettyHttpClient client = NettyHttpClient.builder()
|
||||||
|
|
|
@ -22,6 +22,9 @@ public class JdkClientTest {
|
||||||
System.setProperty("javax.net.debug", "true");
|
System.setProperty("javax.net.debug", "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public JdkClientTest() {
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDNB() throws Exception {
|
public void testDNB() throws Exception {
|
||||||
HttpClient httpClient = HttpClient.newBuilder()
|
HttpClient httpClient = HttpClient.newBuilder()
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package org.xbib.net.http.client.netty.secure.test;
|
package org.xbib.net.http.client.netty.secure.test;
|
||||||
|
|
||||||
|
|
||||||
import org.xbib.net.http.client.BackOff;
|
import org.xbib.net.http.client.BackOff;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -22,6 +21,9 @@ public class MockBackOff implements BackOff {
|
||||||
/** Number of tries so far. */
|
/** Number of tries so far. */
|
||||||
private int numTries;
|
private int numTries;
|
||||||
|
|
||||||
|
public MockBackOff() {
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void reset() {
|
public void reset() {
|
||||||
numTries = 0;
|
numTries = 0;
|
||||||
|
|
|
@ -10,6 +10,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
public class ParameterTest {
|
public class ParameterTest {
|
||||||
|
|
||||||
|
public ParameterTest() {
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetParametersWithSharedUrl() {
|
public void testGetParametersWithSharedUrl() {
|
||||||
URL url = URL.from("http://example.com");
|
URL url = URL.from("http://example.com");
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package org.xbib.net.http.server.application.web.j2html;
|
package org.xbib.net.http.j2html;
|
||||||
|
|
||||||
import org.xbib.net.Attributes;
|
import org.xbib.net.Attributes;
|
||||||
import org.xbib.net.Resource;
|
import org.xbib.net.Resource;
|
||||||
import org.xbib.net.http.j2html.J2HtmlResourceHandler;
|
|
||||||
import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler;
|
import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler;
|
||||||
import org.xbib.net.http.server.route.HttpRouterContext;
|
import org.xbib.net.http.server.route.HttpRouterContext;
|
||||||
import org.xbib.net.util.ExceptionFormatter;
|
import org.xbib.net.util.ExceptionFormatter;
|
|
@ -0,0 +1,34 @@
|
||||||
|
package org.xbib.net.http.j2html;
|
||||||
|
|
||||||
|
import org.xbib.net.Resource;
|
||||||
|
import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler;
|
||||||
|
import org.xbib.net.http.server.route.HttpRouterContext;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public class J2HtmlAuthResourceHandler extends HtmlTemplateResourceHandler {
|
||||||
|
|
||||||
|
public J2HtmlAuthResourceHandler() {
|
||||||
|
this(null, "java", "index.java");
|
||||||
|
}
|
||||||
|
|
||||||
|
public J2HtmlAuthResourceHandler(Path root, String suffix, String indexFileName) {
|
||||||
|
super(root, suffix, indexFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException {
|
||||||
|
return httpRouterContext.isAuthenticated() ?
|
||||||
|
createAuthenticatedResource(httpRouterContext) :
|
||||||
|
createUnauthenticatedResource(httpRouterContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Resource createAuthenticatedResource(HttpRouterContext httpRouterContext) throws IOException {
|
||||||
|
return new J2HtmlResource(this, httpRouterContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Resource createUnauthenticatedResource(HttpRouterContext httpRouterContext) throws IOException {
|
||||||
|
return new J2HtmlResource(this, httpRouterContext);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
package org.xbib.net.http.j2html;
|
||||||
|
|
||||||
|
import org.xbib.net.buffer.DataBuffer;
|
||||||
|
import org.xbib.net.http.HttpResponseStatus;
|
||||||
|
import org.xbib.net.http.server.HttpRequest;
|
||||||
|
import org.xbib.net.http.server.resource.HtmlTemplateResource;
|
||||||
|
import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler;
|
||||||
|
import org.xbib.net.http.server.route.HttpRouterContext;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static org.xbib.j2html.TagCreator.body;
|
||||||
|
import static org.xbib.j2html.TagCreator.h1;
|
||||||
|
import static org.xbib.net.http.HttpHeaderNames.CONTENT_TYPE;
|
||||||
|
|
||||||
|
public class J2HtmlResource extends HtmlTemplateResource {
|
||||||
|
|
||||||
|
protected HttpRequest request;
|
||||||
|
|
||||||
|
public J2HtmlResource(HtmlTemplateResourceHandler templateResourceHandler,
|
||||||
|
HttpRouterContext httpRouterContext) throws IOException {
|
||||||
|
super(templateResourceHandler, httpRouterContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void render(HttpRouterContext context) throws IOException {
|
||||||
|
this.request = context.getRequest();
|
||||||
|
Objects.requireNonNull(responseBuilder);
|
||||||
|
DataBuffer dataBuffer = context.getDataBufferFactory().allocateBuffer();
|
||||||
|
dataBuffer.write(renderBody(context), StandardCharsets.UTF_8);
|
||||||
|
HttpResponseStatus httpResponseStatus = responseBuilder.getResponseStatus();
|
||||||
|
if (httpResponseStatus == null) {
|
||||||
|
httpResponseStatus = HttpResponseStatus.OK;
|
||||||
|
}
|
||||||
|
context.status(httpResponseStatus)
|
||||||
|
.header("cache-control", "no-cache") // override default must-revalidate behavior
|
||||||
|
.header("content-length", Integer.toString(dataBuffer.writePosition()))
|
||||||
|
.header(CONTENT_TYPE, "text/html; charset=" + StandardCharsets.UTF_8.displayName())
|
||||||
|
.body(dataBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rendering a body.
|
||||||
|
* By subclassing this handler, this method should be overridden by custom j2html code.
|
||||||
|
* The body here is just a greeting as an example.
|
||||||
|
*
|
||||||
|
* @param context the router context
|
||||||
|
* @return the body string fo the HTTP response
|
||||||
|
*/
|
||||||
|
protected String renderBody(HttpRouterContext context) {
|
||||||
|
return body(
|
||||||
|
h1("Hello World")
|
||||||
|
).render();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,21 +1,14 @@
|
||||||
package org.xbib.net.http.j2html;
|
package org.xbib.net.http.j2html;
|
||||||
|
|
||||||
import org.xbib.net.Resource;
|
import org.xbib.net.Resource;
|
||||||
import org.xbib.net.buffer.DataBuffer;
|
|
||||||
import org.xbib.net.http.HttpResponseStatus;
|
|
||||||
import org.xbib.net.http.server.HttpRequest;
|
|
||||||
import org.xbib.net.http.server.resource.HtmlTemplateResource;
|
|
||||||
import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler;
|
import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler;
|
||||||
import org.xbib.net.http.server.route.HttpRouterContext;
|
import org.xbib.net.http.server.route.HttpRouterContext;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import static org.xbib.j2html.TagCreator.body;
|
import static org.xbib.j2html.TagCreator.body;
|
||||||
import static org.xbib.j2html.TagCreator.h1;
|
import static org.xbib.j2html.TagCreator.h1;
|
||||||
import static org.xbib.net.http.HttpHeaderNames.CONTENT_TYPE;
|
|
||||||
|
|
||||||
public class J2HtmlResourceHandler extends HtmlTemplateResourceHandler {
|
public class J2HtmlResourceHandler extends HtmlTemplateResourceHandler {
|
||||||
|
|
||||||
|
@ -31,43 +24,4 @@ public class J2HtmlResourceHandler extends HtmlTemplateResourceHandler {
|
||||||
protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException {
|
protected Resource createResource(HttpRouterContext httpRouterContext) throws IOException {
|
||||||
return new J2HtmlResource(this, httpRouterContext);
|
return new J2HtmlResource(this, httpRouterContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static class J2HtmlResource extends HtmlTemplateResource {
|
|
||||||
|
|
||||||
protected HttpRequest request;
|
|
||||||
|
|
||||||
protected J2HtmlResource(HtmlTemplateResourceHandler templateResourceHandler,
|
|
||||||
HttpRouterContext httpRouterContext) throws IOException {
|
|
||||||
super(templateResourceHandler, httpRouterContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void render(HttpRouterContext context) throws IOException {
|
|
||||||
this.request = context.getRequest();
|
|
||||||
Objects.requireNonNull(responseBuilder);
|
|
||||||
DataBuffer dataBuffer = context.getDataBufferFactory().allocateBuffer();
|
|
||||||
dataBuffer.write(renderBody(context), StandardCharsets.UTF_8);
|
|
||||||
HttpResponseStatus httpResponseStatus = responseBuilder.getResponseStatus();
|
|
||||||
if (httpResponseStatus == null) {
|
|
||||||
httpResponseStatus = HttpResponseStatus.OK;
|
|
||||||
}
|
|
||||||
context.status(httpResponseStatus)
|
|
||||||
.header("cache-control", "no-cache") // override default must-revalidate behavior
|
|
||||||
.header("content-length", Integer.toString(dataBuffer.writePosition()))
|
|
||||||
.header(CONTENT_TYPE, "text/html; charset=" + StandardCharsets.UTF_8.displayName())
|
|
||||||
.body(dataBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* By subclassing this handler, this method should be overriden by custom j2html code.
|
|
||||||
* The body here is just a greeting as an example.
|
|
||||||
* @param context the router context
|
|
||||||
* @return the body string fo the HTTP response
|
|
||||||
*/
|
|
||||||
protected String renderBody(HttpRouterContext context) {
|
|
||||||
return body(
|
|
||||||
h1("Hello World")
|
|
||||||
).render();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ import org.xbib.net.http.server.executor.Executor;
|
||||||
import org.xbib.net.http.server.route.HttpRouter;
|
import org.xbib.net.http.server.route.HttpRouter;
|
||||||
import org.xbib.net.http.server.service.HttpService;
|
import org.xbib.net.http.server.service.HttpService;
|
||||||
import org.xbib.net.http.server.auth.BasicAuthenticationHandler;
|
import org.xbib.net.http.server.auth.BasicAuthenticationHandler;
|
||||||
import org.xbib.net.http.server.auth.FormAuthenticationHandler;
|
|
||||||
import org.xbib.net.http.server.ldap.LdapContextFactory;
|
import org.xbib.net.http.server.ldap.LdapContextFactory;
|
||||||
import org.xbib.net.http.server.ldap.LdapGroupMapping;
|
import org.xbib.net.http.server.ldap.LdapGroupMapping;
|
||||||
import org.xbib.net.http.server.ldap.LdapRealm;
|
import org.xbib.net.http.server.ldap.LdapRealm;
|
||||||
|
@ -37,6 +36,7 @@ import org.xbib.net.http.server.netty.secure.HttpsAddress;
|
||||||
import org.xbib.net.http.server.netty.secure.HttpsRequest;
|
import org.xbib.net.http.server.netty.secure.HttpsRequest;
|
||||||
import org.xbib.net.http.server.netty.secure.NettyHttpsServerConfig;
|
import org.xbib.net.http.server.netty.secure.NettyHttpsServerConfig;
|
||||||
import org.xbib.net.http.server.resource.ClassLoaderResourceHandler;
|
import org.xbib.net.http.server.resource.ClassLoaderResourceHandler;
|
||||||
|
import org.xbib.net.http.template.groovy.GroovyFormAuthenticationHandler;
|
||||||
import org.xbib.net.http.template.groovy.GroovyInternalServerErrorHandler;
|
import org.xbib.net.http.template.groovy.GroovyInternalServerErrorHandler;
|
||||||
import org.xbib.net.http.template.groovy.GroovyHttpStatusHandler;
|
import org.xbib.net.http.template.groovy.GroovyHttpStatusHandler;
|
||||||
import org.xbib.net.http.template.groovy.GroovyTemplateResourceHandler;
|
import org.xbib.net.http.template.groovy.GroovyTemplateResourceHandler;
|
||||||
|
@ -125,9 +125,9 @@ public final class Bootstrap {
|
||||||
BasicAuthenticationHandler basicAuthenticationHandler =
|
BasicAuthenticationHandler basicAuthenticationHandler =
|
||||||
new BasicAuthenticationHandler(ldapRealm);
|
new BasicAuthenticationHandler(ldapRealm);
|
||||||
|
|
||||||
FormAuthenticationHandler formAuthenticationHandler =
|
GroovyFormAuthenticationHandler formAuthenticationHandler =
|
||||||
new FormAuthenticationHandler("j_username", "j_password", "j_remember",
|
new GroovyFormAuthenticationHandler("j_username", "j_password",
|
||||||
"demo/auth/form/index.gtpl", ldapRealm);
|
ldapRealm, "demo/auth/form/index.gtpl");
|
||||||
|
|
||||||
HttpSecurityDomain securityDomain = BaseHttpSecurityDomain.builder()
|
HttpSecurityDomain securityDomain = BaseHttpSecurityDomain.builder()
|
||||||
.setSecurityRealm(ldapRealm)
|
.setSecurityRealm(ldapRealm)
|
||||||
|
|
|
@ -5,11 +5,14 @@ import org.xbib.config.ConfigLogger;
|
||||||
import org.xbib.config.ConfigParams;
|
import org.xbib.config.ConfigParams;
|
||||||
import org.xbib.config.SystemConfigLogger;
|
import org.xbib.config.SystemConfigLogger;
|
||||||
import org.xbib.net.NetworkClass;
|
import org.xbib.net.NetworkClass;
|
||||||
|
import org.xbib.net.Resource;
|
||||||
import org.xbib.net.http.HttpHeaderNames;
|
import org.xbib.net.http.HttpHeaderNames;
|
||||||
import org.xbib.net.http.HttpHeaderValues;
|
import org.xbib.net.http.HttpHeaderValues;
|
||||||
import org.xbib.net.http.HttpResponseStatus;
|
import org.xbib.net.http.HttpResponseStatus;
|
||||||
import org.xbib.net.http.HttpVersion;
|
import org.xbib.net.http.HttpVersion;
|
||||||
import org.xbib.net.http.j2html.J2HtmlResourceHandler;
|
import org.xbib.net.http.j2html.InternalServerErrorHandler;
|
||||||
|
import org.xbib.net.http.j2html.J2HtmlAuthResourceHandler;
|
||||||
|
import org.xbib.net.http.j2html.J2HtmlResource;
|
||||||
import org.xbib.net.http.j2html.J2HtmlService;
|
import org.xbib.net.http.j2html.J2HtmlService;
|
||||||
import org.xbib.net.http.server.application.web.WebApplication;
|
import org.xbib.net.http.server.application.web.WebApplication;
|
||||||
import org.xbib.net.http.server.auth.BasicAuthenticationHandler;
|
import org.xbib.net.http.server.auth.BasicAuthenticationHandler;
|
||||||
|
@ -29,12 +32,14 @@ import org.xbib.net.http.server.netty.secure.HttpsAddress;
|
||||||
import org.xbib.net.http.server.netty.secure.HttpsRequest;
|
import org.xbib.net.http.server.netty.secure.HttpsRequest;
|
||||||
import org.xbib.net.http.server.netty.secure.NettyHttpsServerConfig;
|
import org.xbib.net.http.server.netty.secure.NettyHttpsServerConfig;
|
||||||
import org.xbib.net.http.server.resource.ClassLoaderResourceHandler;
|
import org.xbib.net.http.server.resource.ClassLoaderResourceHandler;
|
||||||
|
import org.xbib.net.http.server.resource.HtmlTemplateResourceHandler;
|
||||||
import org.xbib.net.http.server.route.BaseHttpRouter;
|
import org.xbib.net.http.server.route.BaseHttpRouter;
|
||||||
import org.xbib.net.http.server.route.HttpRouter;
|
import org.xbib.net.http.server.route.HttpRouter;
|
||||||
|
import org.xbib.net.http.server.route.HttpRouterContext;
|
||||||
import org.xbib.net.http.server.service.BaseHttpService;
|
import org.xbib.net.http.server.service.BaseHttpService;
|
||||||
import org.xbib.net.http.server.service.HttpService;
|
|
||||||
import org.xbib.settings.Settings;
|
import org.xbib.settings.Settings;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -42,6 +47,9 @@ import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
|
|
||||||
|
import static org.xbib.j2html.TagCreator.body;
|
||||||
|
import static org.xbib.j2html.TagCreator.h1;
|
||||||
|
|
||||||
public final class Bootstrap {
|
public final class Bootstrap {
|
||||||
|
|
||||||
private static final ConfigLogger bootLogger;
|
private static final ConfigLogger bootLogger;
|
||||||
|
@ -125,32 +133,13 @@ public final class Bootstrap {
|
||||||
new BasicAuthenticationHandler(ldapRealm);
|
new BasicAuthenticationHandler(ldapRealm);
|
||||||
|
|
||||||
FormAuthenticationHandler formAuthenticationHandler =
|
FormAuthenticationHandler formAuthenticationHandler =
|
||||||
new FormAuthenticationHandler("j_username", "j_password", "j_remember",
|
new FormAuthenticationHandler("_username", "_password", ldapRealm);
|
||||||
"demo/auth/form/index.gtpl", ldapRealm);
|
|
||||||
|
|
||||||
HttpSecurityDomain securityDomain = BaseHttpSecurityDomain.builder()
|
HttpSecurityDomain securityDomain = BaseHttpSecurityDomain.builder()
|
||||||
.setSecurityRealm(ldapRealm)
|
.setSecurityRealm(ldapRealm)
|
||||||
.setHandlers(formAuthenticationHandler)
|
.setHandlers(formAuthenticationHandler)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
HttpService httpService = BaseHttpService.builder()
|
|
||||||
.setPath("/secure")
|
|
||||||
.setHandler(ctx -> {
|
|
||||||
ctx.status(HttpResponseStatus.OK)
|
|
||||||
.header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
|
|
||||||
.charset(StandardCharsets.UTF_8)
|
|
||||||
.body("secure domain: " +
|
|
||||||
" SNI host = " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() +
|
|
||||||
" SSL session = " + ctx.getRequest().as(HttpsRequest.class).getSSLSession() +
|
|
||||||
" base URL = " + ctx.getRequest().getBaseURL() +
|
|
||||||
" parameter = " + ctx.getRequest().getParameter().toString() +
|
|
||||||
" attributes = " + ctx.getAttributes() +
|
|
||||||
" local address = " + ctx.getRequest().getLocalAddress() +
|
|
||||||
" remote address = " + ctx.getRequest().getRemoteAddress());
|
|
||||||
ctx.done();
|
|
||||||
})
|
|
||||||
.build();
|
|
||||||
|
|
||||||
HttpRouter httpRouter = BaseHttpRouter.builder()
|
HttpRouter httpRouter = BaseHttpRouter.builder()
|
||||||
.setHandler(500, new InternalServerErrorHandler())
|
.setHandler(500, new InternalServerErrorHandler())
|
||||||
.addDomain(BaseHttpDomain.builder()
|
.addDomain(BaseHttpDomain.builder()
|
||||||
|
@ -168,10 +157,27 @@ public final class Bootstrap {
|
||||||
.setPath("/webjars/**")
|
.setPath("/webjars/**")
|
||||||
.setHandler(new ClassLoaderResourceHandler(Bootstrap.class.getClassLoader(), "META-INF/resources/"))
|
.setHandler(new ClassLoaderResourceHandler(Bootstrap.class.getClassLoader(), "META-INF/resources/"))
|
||||||
.build())
|
.build())
|
||||||
.addService(httpService)
|
.addService(BaseHttpService.builder()
|
||||||
|
.setPath("/insecure")
|
||||||
|
.setHandler(ctx -> {
|
||||||
|
ctx.status(HttpResponseStatus.OK)
|
||||||
|
.header(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.TEXT_PLAIN)
|
||||||
|
.charset(StandardCharsets.UTF_8)
|
||||||
|
.body("secure domain: " +
|
||||||
|
" SNI host = " + ctx.getRequest().as(HttpsRequest.class).getSNIHost() +
|
||||||
|
" SSL session = " + ctx.getRequest().as(HttpsRequest.class).getSSLSession() +
|
||||||
|
" base URL = " + ctx.getRequest().getBaseURL() +
|
||||||
|
" parameter = " + ctx.getRequest().getParameter().toString() +
|
||||||
|
" attributes = " + ctx.getAttributes() +
|
||||||
|
" local address = " + ctx.getRequest().getLocalAddress() +
|
||||||
|
" remote address = " + ctx.getRequest().getRemoteAddress());
|
||||||
|
ctx.done();
|
||||||
|
})
|
||||||
|
.build())
|
||||||
.addService(J2HtmlService.builder()
|
.addService(J2HtmlService.builder()
|
||||||
.setPath("glob:**")
|
.setPath("glob:**")
|
||||||
.setHandler(new J2HtmlResourceHandler())
|
.setSecurityDomain(securityDomain)
|
||||||
|
.setHandler(new MyResourceHandler())
|
||||||
.build())
|
.build())
|
||||||
.build())
|
.build())
|
||||||
.build();
|
.build();
|
||||||
|
@ -197,6 +203,47 @@ public final class Bootstrap {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class MyResourceHandler extends J2HtmlAuthResourceHandler {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Resource createAuthenticatedResource(HttpRouterContext httpRouterContext) throws IOException {
|
||||||
|
return new DemoResource(this, httpRouterContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Resource createUnauthenticatedResource(HttpRouterContext httpRouterContext) throws IOException {
|
||||||
|
return new UnauthenticatedDemoResource(this, httpRouterContext);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class DemoResource extends J2HtmlResource {
|
||||||
|
|
||||||
|
public DemoResource(HtmlTemplateResourceHandler templateResourceHandler,
|
||||||
|
HttpRouterContext httpRouterContext) throws IOException {
|
||||||
|
super(templateResourceHandler, httpRouterContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String renderBody(HttpRouterContext context) {
|
||||||
|
return body(
|
||||||
|
h1("This is a demo")
|
||||||
|
).render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class UnauthenticatedDemoResource extends J2HtmlResource {
|
||||||
|
|
||||||
|
public UnauthenticatedDemoResource(HtmlTemplateResourceHandler templateResourceHandler,
|
||||||
|
HttpRouterContext httpRouterContext) throws IOException {
|
||||||
|
super(templateResourceHandler, httpRouterContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String renderBody(HttpRouterContext context) {
|
||||||
|
return body(
|
||||||
|
h1("This is a demo, unauthenticated")
|
||||||
|
).render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static final String hexFavIcon =
|
private static final String hexFavIcon =
|
||||||
"000001000100101000000100200068040000160000002800000010000000" +
|
"000001000100101000000100200068040000160000002800000010000000" +
|
||||||
"200000000100200000000000000000000000000000000000000000000000" +
|
"200000000100200000000000000000000000000000000000000000000000" +
|
||||||
|
|
|
@ -26,6 +26,9 @@ public class SimpleHttpsServerTest {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(SimpleHttpsServerTest.class.getName());
|
private static final Logger logger = Logger.getLogger(SimpleHttpsServerTest.class.getName());
|
||||||
|
|
||||||
|
public SimpleHttpsServerTest() {
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void simpleSecureHttpsServerTest() throws Exception {
|
public void simpleSecureHttpsServerTest() throws Exception {
|
||||||
HttpsAddress httpsAddress = HttpsAddress.builder()
|
HttpsAddress httpsAddress = HttpsAddress.builder()
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.xbib.net.http.server.application;
|
package org.xbib.net.http.server.application;
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
public interface Resolver<R> {
|
public interface Resolver<R> {
|
||||||
|
|
||||||
R resolve(String string);
|
R resolve(String string);
|
||||||
|
|
|
@ -50,6 +50,6 @@ public class BasicAuthenticationHandler extends LoginAuthenticationHandler imple
|
||||||
}
|
}
|
||||||
logger.log(Level.INFO, "unauthenticated");
|
logger.log(Level.INFO, "unauthenticated");
|
||||||
context.status(HttpResponseStatus.UNAUTHORIZED)
|
context.status(HttpResponseStatus.UNAUTHORIZED)
|
||||||
.header("WWW-Authenticate", "Basic realm=\"" + securityRealm.getName() + "\"");
|
.header("WWW-Authenticate", "Basic realm=\"" + getSecurityRealm().getName() + "\"");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,73 +15,60 @@ public class FormAuthenticationHandler extends LoginAuthenticationHandler implem
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(FormAuthenticationHandler.class.getName());
|
private static final Logger logger = Logger.getLogger(FormAuthenticationHandler.class.getName());
|
||||||
|
|
||||||
String usernameParameter;
|
|
||||||
|
|
||||||
String passwordParameter;
|
|
||||||
|
|
||||||
String rememberParameter;
|
|
||||||
|
|
||||||
String loginPage;
|
|
||||||
|
|
||||||
public FormAuthenticationHandler(String usernameParameter,
|
public FormAuthenticationHandler(String usernameParameter,
|
||||||
String passwordParameter,
|
String passwordParameter,
|
||||||
String rememberParameter,
|
|
||||||
String loginPage,
|
|
||||||
SecurityRealm securityRealm) {
|
SecurityRealm securityRealm) {
|
||||||
super(usernameParameter, passwordParameter, securityRealm);
|
super(usernameParameter, passwordParameter, securityRealm);
|
||||||
this.usernameParameter = usernameParameter;
|
|
||||||
this.passwordParameter = passwordParameter;
|
|
||||||
this.rememberParameter = rememberParameter;
|
|
||||||
this.loginPage = loginPage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(HttpRouterContext context) throws IOException {
|
public void handle(HttpRouterContext context) throws IOException {
|
||||||
if (loginPage == null) {
|
|
||||||
logger.log(Level.WARNING, "no loginPage configured");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
UserProfile userProfile = context.getAttributes().get(UserProfile.class, "userprofile");
|
UserProfile userProfile = context.getAttributes().get(UserProfile.class, "userprofile");
|
||||||
if (userProfile != null && userProfile.getUserId() != null) {
|
if (userProfile != null && userProfile.getUserId() != null) {
|
||||||
logger.log(Level.FINE, "user id already set: " + userProfile.getUserId());
|
logger.log(Level.FINE, "user id already set: " + userProfile.getUserId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// always add an "anonymous" user profile
|
if (context.isAuthenticated()) {
|
||||||
|
logger.log(Level.FINE, "context already authenticated");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// always add an "anonymous" user profile with a null user ID
|
||||||
userProfile = new BaseUserProfile();
|
userProfile = new BaseUserProfile();
|
||||||
context.getAttributes().put("userprofile", userProfile);
|
context.getAttributes().put("userprofile", userProfile);
|
||||||
|
boolean isAuthenticated = false;
|
||||||
|
try {
|
||||||
Parameter parameter = context.getRequest().getParameter();
|
Parameter parameter = context.getRequest().getParameter();
|
||||||
if (!parameter.containsKey(usernameParameter, Parameter.Domain.FORM)) {
|
if (!parameter.containsKey(getUserParameterName(), Parameter.Domain.FORM)) {
|
||||||
logger.log(Level.WARNING, "usernameParameter not set, unable to authenticate");
|
logger.log(Level.WARNING, "usernameParameter not set, unable to authenticate");
|
||||||
prepareFormAuthentication(context);
|
prepareFormAuthentication(context);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!parameter.containsKey(passwordParameter, Parameter.Domain.FORM)) {
|
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, "passwordParameter not set, unable to authenticate");
|
||||||
prepareFormAuthentication(context);
|
prepareFormAuthentication(context);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
String password = parameter.getAsString(getPasswordParameterName(), Parameter.Domain.FORM);
|
||||||
String username = parameter.getAsString(usernameParameter, Parameter.Domain.FORM);
|
|
||||||
String password = parameter.getAsString(passwordParameter, Parameter.Domain.FORM);
|
|
||||||
logger.log(Level.FINE, "username and password found, ready for authentication");
|
|
||||||
authenticate(userProfile, username, password, context.getRequest());
|
authenticate(userProfile, username, password, context.getRequest());
|
||||||
logger.log(Level.FINE, "successful authentication");
|
isAuthenticated = true;
|
||||||
return;
|
|
||||||
} catch (ParameterException e) {
|
} catch (ParameterException e) {
|
||||||
logger.log(Level.SEVERE, "parameter error");
|
logger.log(Level.SEVERE, "parameter error");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.log(Level.SEVERE, "authentication error");
|
logger.log(Level.SEVERE, "authentication error");
|
||||||
}
|
} finally {
|
||||||
|
context.setAuthenticated(isAuthenticated);
|
||||||
|
if (!isAuthenticated) {
|
||||||
prepareFormAuthentication(context);
|
prepareFormAuthentication(context);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void prepareFormAuthentication(HttpRouterContext context) {
|
protected void prepareFormAuthentication(HttpRouterContext context) {
|
||||||
// this will redirect internally to login page, and back to the original path.
|
URL origin = context.getContextURL().resolve(context.getRequest().getRequestURI()).normalize();
|
||||||
// We need a full path resolve against the server URL.
|
logger.log(Level.FINE, "context URL = " + context.getContextURL() +
|
||||||
logger.log(Level.FINE, "templatePath = " + loginPage);
|
" request URI = " + context.getRequest().getRequestURI() +
|
||||||
context.getAttributes().put("templatePath", loginPage);
|
" origin = " + origin);
|
||||||
URL loc = context.getContextURL().resolve(context.getRequest().getRequestURI()).normalize();
|
context.getAttributes().put("_origin", origin.toExternalForm());
|
||||||
logger.log(Level.FINE, "context URL = " + context.getContextURL() + " request URI = " + context.getRequest().getRequestURI() + " loc = " + loc);
|
|
||||||
context.getAttributes().put("originalPath", loc.toExternalForm());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import java.util.logging.Logger;
|
||||||
import org.xbib.net.Authenticator;
|
import org.xbib.net.Authenticator;
|
||||||
import org.xbib.net.GroupsProvider;
|
import org.xbib.net.GroupsProvider;
|
||||||
import org.xbib.net.Parameter;
|
import org.xbib.net.Parameter;
|
||||||
|
import org.xbib.net.ParameterException;
|
||||||
import org.xbib.net.Request;
|
import org.xbib.net.Request;
|
||||||
import org.xbib.net.SecurityRealm;
|
import org.xbib.net.SecurityRealm;
|
||||||
import org.xbib.net.UserDetails;
|
import org.xbib.net.UserDetails;
|
||||||
|
@ -23,7 +24,7 @@ public class LoginAuthenticationHandler implements HttpHandler {
|
||||||
|
|
||||||
private final String passwordParameterName;
|
private final String passwordParameterName;
|
||||||
|
|
||||||
protected final SecurityRealm securityRealm;
|
private final SecurityRealm securityRealm;
|
||||||
|
|
||||||
public LoginAuthenticationHandler(String userParameterName,
|
public LoginAuthenticationHandler(String userParameterName,
|
||||||
String passwordParameterName,
|
String passwordParameterName,
|
||||||
|
@ -33,21 +34,39 @@ public class LoginAuthenticationHandler implements HttpHandler {
|
||||||
this.securityRealm = securityRealm;
|
this.securityRealm = securityRealm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getUserParameterName() {
|
||||||
|
return userParameterName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPasswordParameterName() {
|
||||||
|
return passwordParameterName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecurityRealm getSecurityRealm() {
|
||||||
|
return securityRealm;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handle(HttpRouterContext context) throws IOException {
|
public void handle(HttpRouterContext context) throws IOException {
|
||||||
UserProfile userProfile = context.getAttributes().get(UserProfile.class, "userprofile");
|
UserProfile userProfile = context.getAttributes().get(UserProfile.class, "userprofile");
|
||||||
if (userProfile != null && userProfile.getUserId() != null) {
|
if (userProfile != null && userProfile.getUserId() != null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
Parameter parameter = context.getRequest().getParameter();
|
||||||
userProfile = new BaseUserProfile();
|
userProfile = new BaseUserProfile();
|
||||||
try {
|
|
||||||
authenticate(userProfile,
|
|
||||||
(String) context.getRequest().getParameter().get(userParameterName, Parameter.Domain.FORM),
|
|
||||||
(String) context.getRequest().getParameter().get(passwordParameterName, Parameter.Domain.FORM),
|
|
||||||
context.getRequest());
|
|
||||||
context.getAttributes().put("userprofile", userProfile);
|
context.getAttributes().put("userprofile", userProfile);
|
||||||
|
boolean isAuthenticated = false;
|
||||||
|
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;
|
||||||
|
} catch (ParameterException e) {
|
||||||
|
logger.log(Level.SEVERE, "parameter error");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.log(Level.SEVERE, "authentication error");
|
logger.log(Level.SEVERE, "authentication error");
|
||||||
|
} finally {
|
||||||
|
context.setAuthenticated(isAuthenticated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,8 @@ public class BaseHttpRouterContext implements HttpRouterContext {
|
||||||
|
|
||||||
private boolean next;
|
private boolean next;
|
||||||
|
|
||||||
|
private boolean isAuthenticated;
|
||||||
|
|
||||||
public BaseHttpRouterContext(Application application,
|
public BaseHttpRouterContext(Application application,
|
||||||
HttpDomain domain,
|
HttpDomain domain,
|
||||||
HttpRequestBuilder httpRequestBuilder,
|
HttpRequestBuilder httpRequestBuilder,
|
||||||
|
@ -280,6 +282,15 @@ public class BaseHttpRouterContext implements HttpRouterContext {
|
||||||
return httpResponseBuilder.getLength();
|
return httpResponseBuilder.getLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setAuthenticated(boolean isAuthenticated) {
|
||||||
|
this.isAuthenticated = isAuthenticated;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAuthenticated() {
|
||||||
|
return isAuthenticated;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void flush() throws IOException {
|
public void flush() throws IOException {
|
||||||
httpResponseBuilder.build().flush();
|
httpResponseBuilder.build().flush();
|
||||||
|
|
|
@ -97,6 +97,10 @@ public interface HttpRouterContext {
|
||||||
|
|
||||||
long lengthInBytes();
|
long lengthInBytes();
|
||||||
|
|
||||||
|
void setAuthenticated(boolean isAuthenticated);
|
||||||
|
|
||||||
|
boolean isAuthenticated();
|
||||||
|
|
||||||
void flush() throws IOException;
|
void flush() throws IOException;
|
||||||
|
|
||||||
void close() throws IOException;
|
void close() throws IOException;
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
package org.xbib.net.http.template.groovy;
|
||||||
|
|
||||||
|
import org.xbib.net.Parameter;
|
||||||
|
import org.xbib.net.ParameterException;
|
||||||
|
import org.xbib.net.SecurityRealm;
|
||||||
|
import org.xbib.net.URL;
|
||||||
|
import org.xbib.net.UserProfile;
|
||||||
|
import org.xbib.net.http.server.auth.BaseUserProfile;
|
||||||
|
import org.xbib.net.http.server.auth.FormAuthenticationHandler;
|
||||||
|
import org.xbib.net.http.server.route.HttpRouterContext;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
public class GroovyFormAuthenticationHandler extends FormAuthenticationHandler {
|
||||||
|
|
||||||
|
private static final Logger logger = Logger.getLogger(GroovyFormAuthenticationHandler.class.getName());
|
||||||
|
|
||||||
|
private final String loginTemplate;
|
||||||
|
|
||||||
|
public GroovyFormAuthenticationHandler(String usernameParameter,
|
||||||
|
String passwordParameter,
|
||||||
|
SecurityRealm securityRealm,
|
||||||
|
String loginTemplate) {
|
||||||
|
super(usernameParameter, passwordParameter, securityRealm);
|
||||||
|
this.loginTemplate = Objects.requireNonNull(loginTemplate, "no login template configured");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(HttpRouterContext context) throws IOException {
|
||||||
|
UserProfile userProfile = context.getAttributes().get(UserProfile.class, "userprofile");
|
||||||
|
if (userProfile != null && userProfile.getUserId() != null) {
|
||||||
|
logger.log(Level.FINE, "user id already set: " + userProfile.getUserId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// always add an "anonymous" user profile
|
||||||
|
userProfile = new BaseUserProfile();
|
||||||
|
context.getAttributes().put("userprofile", userProfile);
|
||||||
|
Parameter parameter = context.getRequest().getParameter();
|
||||||
|
if (!parameter.containsKey(getUserParameterName(), Parameter.Domain.FORM)) {
|
||||||
|
logger.log(Level.WARNING, "usernameParameter not set, unable to authenticate");
|
||||||
|
prepareFormAuthentication(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!parameter.containsKey(getPasswordParameterName(), Parameter.Domain.FORM)) {
|
||||||
|
logger.log(Level.WARNING, "passwordParameter not set, unable to authenticate");
|
||||||
|
prepareFormAuthentication(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
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;
|
||||||
|
} catch (ParameterException e) {
|
||||||
|
logger.log(Level.SEVERE, "parameter error");
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "authentication error");
|
||||||
|
}
|
||||||
|
prepareFormAuthentication(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void prepareFormAuthentication(HttpRouterContext context) {
|
||||||
|
// this will redirect internally to login page, and back to the original path.
|
||||||
|
// 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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -50,7 +50,7 @@ public class GroovyTemplateServiceBuilder extends BaseHttpServiceBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseHttpServiceBuilder setSecurityDomain(HttpSecurityDomain securityDomain) {
|
public GroovyTemplateServiceBuilder setSecurityDomain(HttpSecurityDomain securityDomain) {
|
||||||
super.setSecurityDomain(securityDomain);
|
super.setSecurityDomain(securityDomain);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue