diff --git a/jans-linux-setup/jans_setup/templates/jans-lock/dynamic-conf.json b/jans-linux-setup/jans_setup/templates/jans-lock/dynamic-conf.json index 83289089583..f9b46fe325a 100644 --- a/jans-linux-setup/jans_setup/templates/jans-lock/dynamic-conf.json +++ b/jans-linux-setup/jans_setup/templates/jans-lock/dynamic-conf.json @@ -1,4 +1,6 @@ { + "baseEndpoint" : "https://%(hostname)s/jans-lock/v1", + "tokenChannels":[ "jans_token" ], diff --git a/jans-lock/lock-master/model/src/main/java/io/jans/lock/model/config/AppConfiguration.java b/jans-lock/lock-master/model/src/main/java/io/jans/lock/model/config/AppConfiguration.java index 2c1f314f783..277c1b33061 100644 --- a/jans-lock/lock-master/model/src/main/java/io/jans/lock/model/config/AppConfiguration.java +++ b/jans-lock/lock-master/model/src/main/java/io/jans/lock/model/config/AppConfiguration.java @@ -24,11 +24,13 @@ public class AppConfiguration implements Configuration { private String baseDN; + + @DocProperty(description = "Lock base endpoint URL") + private String baseEndpoint; @DocProperty(description = "List of token channel names", defaultValue = "jans_token") private List tokenChannels; - @DocProperty(description = "Choose whether to disable JDK loggers", defaultValue = "true") private Boolean disableJdkLogger = true; @@ -82,6 +84,14 @@ public void setBaseDN(String baseDN) { this.baseDN = baseDN; } + public String getBaseEndpoint() { + return baseEndpoint; + } + + public void setBaseEndpoint(String baseEndpoint) { + this.baseEndpoint = baseEndpoint; + } + public List getTokenChannels() { if (tokenChannels == null) { tokenChannels = new ArrayList<>(); diff --git a/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/util/ResteasyInitializer.java b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/util/ResteasyInitializer.java new file mode 100644 index 00000000000..da1cd50ba61 --- /dev/null +++ b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/util/ResteasyInitializer.java @@ -0,0 +1,37 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2024, Janssen Project + */ + +package io.jans.lock.service.util; + +import java.util.HashSet; +import java.util.Set; + +import io.jans.lock.service.ws.rs.ConfigurationRestWebService; +import io.jans.lock.service.ws.rs.audit.AuditRestWebServiceImpl; +import io.jans.lock.service.ws.rs.sse.SseRestWebServiceImpl; +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; + + +/** + * Integration with Resteasy + * + * @author Yuriy Movchan Date: 06/06/2024 + */ +@ApplicationPath("/v1") +public class ResteasyInitializer extends Application { + + @Override + public Set> getClasses() { + HashSet> classes = new HashSet>(); + classes.add(AuditRestWebServiceImpl.class); + classes.add(ConfigurationRestWebService.class); + classes.add(SseRestWebServiceImpl.class); + + return classes; + } + +} diff --git a/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/util/ServerUtil.java b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/util/ServerUtil.java new file mode 100644 index 00000000000..b4803a808ba --- /dev/null +++ b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/util/ServerUtil.java @@ -0,0 +1,46 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2024, Janssen Project + */ + +package io.jans.lock.service.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.ws.rs.core.CacheControl; + +/** + * @author Yuriy Zabrovarnyy + * @author Yuriy Movchan + * @version 0.9, 26/12/2012 + */ + +public class ServerUtil { + + private static final Logger log = LoggerFactory.getLogger(ServerUtil.class); + + public static final String PRAGMA = "Pragma"; + public static final String NO_CACHE = "no-cache"; + + public static CacheControl cacheControl(boolean noStore) { + final CacheControl cacheControl = new CacheControl(); + cacheControl.setNoStore(noStore); + return cacheControl; + } + + public static CacheControl cacheControl(boolean noStore, boolean noTransform) { + final CacheControl cacheControl = new CacheControl(); + cacheControl.setNoStore(noStore); + cacheControl.setNoTransform(noTransform); + return cacheControl; + } + + public static CacheControl cacheControlWithNoStoreTransformAndPrivate() { + final CacheControl cacheControl = cacheControl(true, false); + cacheControl.setPrivate(true); + return cacheControl; + } + +} diff --git a/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/ConfigurationRestWebService.java b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/ConfigurationRestWebService.java new file mode 100644 index 00000000000..fb6170a7882 --- /dev/null +++ b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/ConfigurationRestWebService.java @@ -0,0 +1,74 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2024, Janssen Project + */ + +package io.jans.lock.service.ws.rs; + +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.ResponseBuilder; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import io.jans.lock.model.config.AppConfiguration; +import io.jans.service.net.NetworkService; + +/** + * Lock metadata configuration + * + * @author Yuriy Movchan Date: 12/19/2018 + */ +@ApplicationScoped +@Path("/configuration") +public class ConfigurationRestWebService { + + @Inject + private AppConfiguration appConfiguration; + + @Inject + private NetworkService networkService; + + private ObjectMapper objectMapper; + + @PostConstruct + public void init() { + this.objectMapper = new ObjectMapper(); + } + + @GET + @Produces({ "application/json" }) + public Response getConfiguration() { + final String baseEndpointUri = appConfiguration.getBaseEndpoint(); + ObjectNode response = objectMapper.createObjectNode(); + + response.put("version", "1.0"); + response.put("issuer", networkService.getHost(baseEndpointUri)); + + ObjectNode audit = objectMapper.createObjectNode(); + response.set("audit", audit); + audit.put("health_endpoint", baseEndpointUri + "/audit/health"); + audit.put("log_endpoint", baseEndpointUri + "/audit/log"); + audit.put("telemetry_endpoint", baseEndpointUri + "/audit/telemetry"); + + ObjectNode config = objectMapper.createObjectNode(); + response.set("config", config); + config.put("config_endpoint", baseEndpointUri + "/config"); + config.put("issuers_endpoint", baseEndpointUri + "/config/issuers"); + config.put("policy_endpoint", baseEndpointUri + "/config/policy"); + config.put("schema_endpoint", baseEndpointUri + "/config/schema"); + + config.put("sse_endpoint", baseEndpointUri + "/sse"); + + ResponseBuilder builder = Response.ok().entity(response.toString()); + return builder.build(); + } + +} diff --git a/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/audit/AuditRestWebService.java b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/audit/AuditRestWebService.java new file mode 100644 index 00000000000..0de2a2b5d0a --- /dev/null +++ b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/audit/AuditRestWebService.java @@ -0,0 +1,42 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2024, Janssen Project + */ + +package io.jans.lock.service.ws.rs.audit; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; + +/** + * Provides interface for audit REST web services + * + * @author Yuriy Movchan Date: 05/24/2024 + */ +public interface AuditRestWebService { + + @POST + @Path("/audit/health") + @Produces({ MediaType.APPLICATION_JSON }) + Response processHealthRequest(@Context HttpServletRequest request, @Context HttpServletResponse response, @Context SecurityContext sec); + + @POST + @Path("/audit//log") + @Produces({ MediaType.APPLICATION_JSON }) + Response processLogRequest(@Context HttpServletRequest request, @Context HttpServletResponse response, @Context SecurityContext sec); + + @POST + @Path("/audit//telemetry") + @Produces({ MediaType.APPLICATION_JSON }) + Response processTelemetryRequest(@Context HttpServletRequest request, @Context HttpServletResponse response, + @Context SecurityContext sec); + +} \ No newline at end of file diff --git a/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/audit/AuditRestWebServiceImpl.java b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/audit/AuditRestWebServiceImpl.java new file mode 100644 index 00000000000..acbab0f1017 --- /dev/null +++ b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/audit/AuditRestWebServiceImpl.java @@ -0,0 +1,64 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2024, Janssen Project + */ + +package io.jans.lock.service.ws.rs.audit; + +import org.slf4j.Logger; + +import io.jans.lock.service.util.ServerUtil; +import jakarta.inject.Inject; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; + +/** + * Provides interface for audit REST web services + * + * @author Yuriy Movchan Date: 06/06/2024 + */ +public class AuditRestWebServiceImpl implements AuditRestWebService { + + @Inject + private Logger log; + + @Override + public Response processHealthRequest(HttpServletRequest request, HttpServletResponse response, SecurityContext sec) { + log.debug("Processing Health request"); + Response.ResponseBuilder builder = Response.ok(); + + builder.cacheControl(ServerUtil.cacheControlWithNoStoreTransformAndPrivate()); + builder.header(ServerUtil.PRAGMA, ServerUtil.NO_CACHE); + builder.entity("{\"res\" : \"ok\"}"); + + return builder.build(); + } + + @Override + public Response processLogRequest(HttpServletRequest request, HttpServletResponse response, SecurityContext sec) { + log.debug("Processing Log request"); + Response.ResponseBuilder builder = Response.ok(); + + builder.cacheControl(ServerUtil.cacheControlWithNoStoreTransformAndPrivate()); + builder.header(ServerUtil.PRAGMA, ServerUtil.NO_CACHE); + builder.entity("{\"res\" : \"ok\"}"); + + return builder.build(); + } + + @Override + public Response processTelemetryRequest(HttpServletRequest request, HttpServletResponse response, SecurityContext sec) { + log.debug("Processing Telemetry request"); + Response.ResponseBuilder builder = Response.ok(); + + builder.cacheControl(ServerUtil.cacheControlWithNoStoreTransformAndPrivate()); + builder.header(ServerUtil.PRAGMA, ServerUtil.NO_CACHE); + builder.entity("{\"res\" : \"ok\"}"); + + return builder.build(); + } + +} diff --git a/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/config/ConfigRestWebService.java b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/config/ConfigRestWebService.java new file mode 100644 index 00000000000..dbd3052a74e --- /dev/null +++ b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/config/ConfigRestWebService.java @@ -0,0 +1,47 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2024, Janssen Project + */ + +package io.jans.lock.service.ws.rs.config; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; + +/** + * Provides interface for configuration REST web services + * + * @author Yuriy Movchan Date: 06/06/2024 + */ +public interface ConfigRestWebService { + + @GET + @Path("/config") + @Produces({ MediaType.APPLICATION_JSON }) + Response processConfigRequest(@Context HttpServletRequest request, @Context HttpServletResponse response, @Context SecurityContext sec); + + @GET + @Path("/config/issuers") + @Produces({ MediaType.APPLICATION_JSON }) + Response processIssuersRequest(@Context HttpServletRequest request, @Context HttpServletResponse response, + @Context SecurityContext sec); + + @GET + @Path("/config/policy") + @Produces({ MediaType.APPLICATION_JSON }) + Response processPolicyRequest(@Context HttpServletRequest request, @Context HttpServletResponse response, @Context SecurityContext sec); + + @GET + @Path("​/config​/schema") + @Produces({ MediaType.APPLICATION_JSON }) + Response processSchemaRequest(@Context HttpServletRequest request, @Context HttpServletResponse response, @Context SecurityContext sec); + +} \ No newline at end of file diff --git a/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/config/ConfigRestWebServiceImpl.java b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/config/ConfigRestWebServiceImpl.java new file mode 100644 index 00000000000..d6f3d85e581 --- /dev/null +++ b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/config/ConfigRestWebServiceImpl.java @@ -0,0 +1,76 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2024, Janssen Project + */ + +package io.jans.lock.service.ws.rs.config; + +import org.slf4j.Logger; + +import io.jans.lock.service.util.ServerUtil; +import jakarta.inject.Inject; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; + +/** + * Provides interface for сщташп REST web services + * + * @author Yuriy Movchan Date: 06/06/2024 + */ +public class ConfigRestWebServiceImpl implements ConfigRestWebService { + + @Inject + private Logger log; + + @Override + public Response processConfigRequest(HttpServletRequest request, HttpServletResponse response, SecurityContext sec) { + log.debug("Processing Config request"); + Response.ResponseBuilder builder = Response.ok(); + + builder.cacheControl(ServerUtil.cacheControlWithNoStoreTransformAndPrivate()); + builder.header(ServerUtil.PRAGMA, ServerUtil.NO_CACHE); + builder.entity("{\"res\" : \"ok\"}"); + + return builder.build(); + } + + @Override + public Response processIssuersRequest(HttpServletRequest request, HttpServletResponse response, SecurityContext sec) { + log.debug("Processing Issuers request"); + Response.ResponseBuilder builder = Response.ok(); + + builder.cacheControl(ServerUtil.cacheControlWithNoStoreTransformAndPrivate()); + builder.header(ServerUtil.PRAGMA, ServerUtil.NO_CACHE); + builder.entity("{\"res\" : \"ok\"}"); + + return builder.build(); + } + + @Override + public Response processPolicyRequest(HttpServletRequest request, HttpServletResponse response, SecurityContext sec) { + log.debug("Processing Policy request"); + Response.ResponseBuilder builder = Response.ok(); + + builder.cacheControl(ServerUtil.cacheControlWithNoStoreTransformAndPrivate()); + builder.header(ServerUtil.PRAGMA, ServerUtil.NO_CACHE); + builder.entity("{\"res\" : \"ok\"}"); + + return builder.build(); + } + + @Override + public Response processSchemaRequest(HttpServletRequest request, HttpServletResponse response, SecurityContext sec) { + log.debug("Processing Schema request"); + Response.ResponseBuilder builder = Response.ok(); + + builder.cacheControl(ServerUtil.cacheControlWithNoStoreTransformAndPrivate()); + builder.header(ServerUtil.PRAGMA, ServerUtil.NO_CACHE); + builder.entity("{\"res\" : \"ok\"}"); + + return builder.build(); + } + +} diff --git a/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/sse/SseRestWebService.java b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/sse/SseRestWebService.java new file mode 100644 index 00000000000..37ff6e7800e --- /dev/null +++ b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/sse/SseRestWebService.java @@ -0,0 +1,26 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2024, Janssen Project + */ + +package io.jans.lock.service.ws.rs.sse; + +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.sse.SseEventSink; + +/** + * @author Yuriy Movchan Date: 05/24/2024 + */ +@Path("/sse") +public interface SseRestWebService { + + @GET + @Produces(MediaType.SERVER_SENT_EVENTS) + public void subscribe(@Context SseEventSink sseEventSink); + +} \ No newline at end of file diff --git a/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/sse/SseRestWebServiceImpl.java b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/sse/SseRestWebServiceImpl.java new file mode 100644 index 00000000000..df5d8792e35 --- /dev/null +++ b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/sse/SseRestWebServiceImpl.java @@ -0,0 +1,32 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2024, Janssen Project + */ + +package io.jans.lock.service.ws.rs.sse; + +import jakarta.inject.Inject; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.sse.SseEventSink; + +/** + * @author Yuriy Movchan Date: 05/24/2024 + */ +@Path("/sse") +public class SseRestWebServiceImpl implements SseRestWebService { + + @Inject + private TokenSseBroadcater tokenSseBroadcater; + + @GET + @Produces(MediaType.SERVER_SENT_EVENTS) + public void subscribe(@Context SseEventSink sseEventSink) { + tokenSseBroadcater.register(sseEventSink); + } + +} diff --git a/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/sse/TokenSseBroadcater.java b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/sse/TokenSseBroadcater.java new file mode 100644 index 00000000000..1f899e63b91 --- /dev/null +++ b/jans-lock/lock-master/service/src/main/java/io/jans/lock/service/ws/rs/sse/TokenSseBroadcater.java @@ -0,0 +1,59 @@ +/* + * Janssen Project software is available under the Apache License (2004). See http://www.apache.org/licenses/ for full text. + * + * Copyright (c) 2024, Janssen Project + */ + +package io.jans.lock.service.ws.rs.sse; + +import org.slf4j.Logger; + +import io.jans.lock.service.policy.event.PolicyDownloadEvent; +import io.jans.service.cdi.async.Asynchronous; +import io.jans.service.cdi.event.Scheduled; +import jakarta.annotation.PostConstruct; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.enterprise.event.Observes; +import jakarta.inject.Inject; +import jakarta.ws.rs.sse.OutboundSseEvent; +import jakarta.ws.rs.sse.Sse; +import jakarta.ws.rs.sse.SseBroadcaster; +import jakarta.ws.rs.sse.SseEventSink; + +/** + * @author Yuriy Movchan Date: 05/24/2024 + */ +@ApplicationScoped +public class TokenSseBroadcater { + + @Inject + private Logger log; + + @Inject + private Sse sse; + + @Inject + private SseBroadcaster sseBroadcaster; + + @PostConstruct + public void init() { + log.info("Initializing Token SSE broadcaster ..."); + this.sseBroadcaster = sse.newBroadcaster(); + } + + @Asynchronous + public void reloadPoliciesTimerEvent(@Observes @Scheduled PolicyDownloadEvent policyDownloadEvent) { + // test messages + broadcast("token_list", "{\"sample_data\" : \"data\"}"); + } + + public void broadcast(String eventName, String data) { + OutboundSseEvent event = sse.newEventBuilder().name(eventName).data(String.class, data).build(); + sseBroadcaster.broadcast(event); + } + + public void register(SseEventSink sseEventSink) { + sseBroadcaster.register(sseEventSink); + } + +}