From 3f954207eeae40b5bbbd6225c0e7240db12dd3d4 Mon Sep 17 00:00:00 2001 From: BarDweller Date: Tue, 28 Jun 2022 18:29:55 -0400 Subject: [PATCH] Remove non native working bits, alter logging. --- .../signed/SignedClientRequestFilter.java | 4 +-- .../signed/SignedContainerRequestFilter.java | 19 ++++++---- .../java/org/gameontext/signed/SignedJWT.java | 2 +- .../gameontext/signed/SignedJWTValidator.java | 6 ++-- .../org/gameontext/signed/SignedLogger.java | 29 +++++++++++++++ .../signed/SignedReaderInterceptor.java | 4 +-- .../signed/SignedRequestFeature.java | 28 ++++----------- .../signed/SignedRequestTimedCache.java | 35 ++++++++----------- .../signed/SignedWriterInterceptor.java | 2 +- 9 files changed, 70 insertions(+), 59 deletions(-) create mode 100644 src/main/java/org/gameontext/signed/SignedLogger.java diff --git a/src/main/java/org/gameontext/signed/SignedClientRequestFilter.java b/src/main/java/org/gameontext/signed/SignedClientRequestFilter.java index b30ef16..57b4487 100644 --- a/src/main/java/org/gameontext/signed/SignedClientRequestFilter.java +++ b/src/main/java/org/gameontext/signed/SignedClientRequestFilter.java @@ -89,7 +89,7 @@ public void filter(ClientRequestContext requestContext) throws IOException { SignedRequestMap headers = new SignedRequestMap.MVSO_StringMap(requestContext.getHeaders()); SignedRequestMap parameters = new SignedRequestMap.QueryParameterMap(requestContext.getUri().getRawQuery()); - SignedRequestFeature.writeLog(Level.FINEST, this, "REQUEST FILTER: USER={0}, PATH={1}, QUERY={2}, HEADERS={3}, HAS_ENTITY={4}", + SignedLogger.writeLog(Level.FINEST, this, "REQUEST FILTER: USER={0}, PATH={1}, QUERY={2}, HEADERS={3}, HAS_ENTITY={4}", userId, requestContext.getMethod() + " " + requestContext.getUri().getRawPath(), requestContext.getUri().getRawQuery(), @@ -120,7 +120,7 @@ public void filter(ClientRequestContext requestContext) throws IOException { e, Response.Status.INTERNAL_SERVER_ERROR); } - SignedRequestFeature.writeLog(Level.FINEST, this, "CLIENT FILTER: {0} {1} {2}", invalidHmacEx, clientHmac, headers); + SignedLogger.writeLog(Level.FINEST, this, "CLIENT FILTER: {0} {1} {2}", invalidHmacEx, clientHmac, headers); if ( invalidHmacEx != null ) { // STOP!! turn this right around with the bad response diff --git a/src/main/java/org/gameontext/signed/SignedContainerRequestFilter.java b/src/main/java/org/gameontext/signed/SignedContainerRequestFilter.java index 2e2d7e3..f5aaec6 100644 --- a/src/main/java/org/gameontext/signed/SignedContainerRequestFilter.java +++ b/src/main/java/org/gameontext/signed/SignedContainerRequestFilter.java @@ -45,7 +45,7 @@ public SignedContainerRequestFilter(SignedRequestSecretProvider playerClient, Si this.timedCache = timedCache; if ( playerClient == null || timedCache == null ) { - SignedRequestFeature.writeLog(Level.SEVERE, this, + SignedLogger.writeLog(Level.SEVERE, this, "Required resources are not available: playerClient={0}, timedCache={1}", playerClient, timedCache); throw new IllegalStateException("Required resources are not available"); @@ -70,13 +70,14 @@ public SignedContainerRequestFilter(SignedRequestSecretProvider playerClient, Si */ @Override public void filter(ContainerRequestContext requestContext) throws IOException { + WebApplicationException invalidHmacEx = null; SignedRequestHmac hmac = null; String userId = requestContext.getHeaderString(SignedRequestHmac.GAMEON_ID); String method = requestContext.getMethod(); - SignedRequestFeature.writeLog(Level.FINEST, this, "REQUEST FILTER: USER={0}, PATH={1}, QUERY={2}, HEADERS={3}", + SignedLogger.writeLog(Level.FINEST, this, "REQUEST FILTER: USER={0}, PATH={1}, QUERY={2}, HEADERS={3}", userId, method + " " + requestContext.getUriInfo().getAbsolutePath().getRawPath(), requestContext.getUriInfo().getQueryParameters(false), @@ -86,23 +87,25 @@ public void filter(ContainerRequestContext requestContext) throws IOException { if ( "GET".equals(method) ) { // no validation required for GET requests. If an ID isn't provided, // then we won't do validation and will just return. - SignedRequestFeature.writeLog(Level.FINEST, this, "FILTER: GET WITH NO ID-- NO VERIFICATION"); + SignedLogger.writeLog(Level.FINEST, this, "FILTER: GET WITH NO ID-- NO VERIFICATION"); return; } else { //debug empty userid header.. if(userId!=null){ BufferedReader buffer = new BufferedReader(new InputStreamReader(requestContext.getEntityStream(), SignedRequestHmac.UTF8)); String body = buffer.lines().collect(Collectors.joining("\n")); - SignedRequestFeature.writeLog(Level.FINEST,this,"BODY: "+body); + SignedLogger.writeLog(Level.FINEST,this,"BODY: "+body); } - SignedRequestFeature.writeLog(Level.FINEST, this, "FILTER: "+method+" WITH NO ID-- UNAUTHORIZED"); + SignedLogger.writeLog(Level.FINEST, this, "FILTER: "+method+" WITH NO ID-- UNAUTHORIZED"); // STOP!! turn this right around with the bad response requestContext.abortWith(Response.status(Status.FORBIDDEN).build()); return; } } + SignedLogger.writeLog(Level.FINEST, this, "FILTER: ID PRESENT.. VALIDATING..."); + try { SignedRequestMap headers = new SignedRequestMap.MVSS_StringMap(requestContext.getHeaders()); SignedRequestMap query = new SignedRequestMap.MVSS_StringMap(requestContext.getUriInfo().getQueryParameters(false)); @@ -121,7 +124,9 @@ public void filter(ContainerRequestContext requestContext) throws IOException { // @see SignedReaderInterceptor as assigned by SignedRequestFeature requestContext.setProperty("SignedRequestHmac", hmac); } else { + SignedLogger.writeLog(Level.FINEST, this, "FILTER: verifying hmac"); hmac.verifyFullSignature(); + SignedLogger.writeLog(Level.FINEST, this, "FILTER: hmac verified"); } } catch(WebApplicationException ex) { invalidHmacEx = ex; @@ -131,9 +136,11 @@ public void filter(ContainerRequestContext requestContext) throws IOException { } requestContext.setProperty("player.id", userId); - SignedRequestFeature.writeLog(Level.FINEST, this, "FILTER: {0} {1}", invalidHmacEx, hmac); + SignedLogger.writeLog(Level.FINEST, this, "FILTER: {0} {1}", invalidHmacEx, hmac); if ( invalidHmacEx != null ) { + invalidHmacEx.printStackTrace(); + // STOP!! turn this right around with the bad response requestContext.abortWith(invalidHmacEx.getResponse()); } diff --git a/src/main/java/org/gameontext/signed/SignedJWT.java b/src/main/java/org/gameontext/signed/SignedJWT.java index 0b98655..2061bb6 100644 --- a/src/main/java/org/gameontext/signed/SignedJWT.java +++ b/src/main/java/org/gameontext/signed/SignedJWT.java @@ -99,7 +99,7 @@ private AuthenticationState processSources(PublicKey key, String[] sources) { code = FailureCode.NONE; } catch (ParseException e) { code = FailureCode.BAD_SIGNATURE; - SignedRequestFeature.writeLog(Level.WARNING, this, "JWT failed validation {0}. {1}", e.getMessage(), token); + SignedLogger.writeLog(Level.WARNING, this, "JWT failed validation {0}. {1}", e.getMessage(), token); } } diff --git a/src/main/java/org/gameontext/signed/SignedJWTValidator.java b/src/main/java/org/gameontext/signed/SignedJWTValidator.java index c56ae44..f162976 100644 --- a/src/main/java/org/gameontext/signed/SignedJWTValidator.java +++ b/src/main/java/org/gameontext/signed/SignedJWTValidator.java @@ -16,7 +16,6 @@ package org.gameontext.signed; import java.io.ByteArrayInputStream; -import java.nio.charset.StandardCharsets; import java.security.cert.Certificate; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; @@ -33,14 +32,13 @@ import javax.enterprise.context.ApplicationScoped; import org.eclipse.microprofile.config.ConfigProvider; -import org.jose4j.jwt.JwtClaims; -import org.jose4j.jwt.consumer.InvalidJwtException; -import io.smallrye.jwt.auth.principal.JWTCallerPrincipal; +import io.quarkus.arc.Unremovable; import io.smallrye.jwt.build.Jwt; import io.smallrye.jwt.build.JwtClaimsBuilder; @ApplicationScoped +@Unremovable public class SignedJWTValidator { diff --git a/src/main/java/org/gameontext/signed/SignedLogger.java b/src/main/java/org/gameontext/signed/SignedLogger.java new file mode 100644 index 0000000..9dca96a --- /dev/null +++ b/src/main/java/org/gameontext/signed/SignedLogger.java @@ -0,0 +1,29 @@ +package org.gameontext.signed; + +import java.util.logging.Level; +import java.util.logging.Logger; + +public class SignedLogger { + + final static Logger logger = Logger.getLogger("org.gameontext.signed"); + + final static void writeLog(Level level, Object source, String message, Object... args) { + + //hack hack.. can't enable FINEST for native apps??!! + if(level.equals(Level.FINEST))level = Level.FINER; + + if (logger.isLoggable(level)) { + logger.logp(level, source.getClass().getName(), "", message, args); + } + } + + final static void writeLog(Level level, Object source, String message, Throwable thrown) { + + //hack hack.. can't enable FINEST for native apps??!! + if(level.equals(Level.FINEST))level = Level.FINER; + + if (logger.isLoggable(level)) { + logger.logp(level, source.getClass().getName(), "", message, thrown); + } + } +} diff --git a/src/main/java/org/gameontext/signed/SignedReaderInterceptor.java b/src/main/java/org/gameontext/signed/SignedReaderInterceptor.java index 40de795..70d2ca2 100644 --- a/src/main/java/org/gameontext/signed/SignedReaderInterceptor.java +++ b/src/main/java/org/gameontext/signed/SignedReaderInterceptor.java @@ -40,8 +40,8 @@ public Object aroundReadFrom(ReaderInterceptorContext context) throws IOExceptio SignedRequestHmac hmac = (SignedRequestHmac) context.getProperty("SignedRequestHmac"); if ( hmac != null ) { - // Fully read request body + // Fully read request body BufferedReader buffer = new BufferedReader(new InputStreamReader(context.getInputStream(), SignedRequestHmac.UTF8)); String body = buffer.lines().collect(Collectors.joining("\n")); byte[] bodyBytes = body.getBytes(SignedRequestHmac.UTF8); @@ -55,7 +55,7 @@ public Object aroundReadFrom(ReaderInterceptorContext context) throws IOExceptio // what we read... context.setInputStream(new ByteArrayInputStream(bodyBytes)); } - SignedRequestFeature.writeLog(Level.FINEST, this, "READER INTERCEPTOR: {0} {1}", hmac); + SignedLogger.writeLog(Level.FINEST, this, "READER INTERCEPTOR: {0} {1}", hmac); } return context.proceed(); } diff --git a/src/main/java/org/gameontext/signed/SignedRequestFeature.java b/src/main/java/org/gameontext/signed/SignedRequestFeature.java index 7d88dc6..74816f6 100644 --- a/src/main/java/org/gameontext/signed/SignedRequestFeature.java +++ b/src/main/java/org/gameontext/signed/SignedRequestFeature.java @@ -15,10 +15,6 @@ *******************************************************************************/ package org.gameontext.signed; -import java.util.logging.Level; -import java.util.logging.Logger; - -import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.spi.CDI; import javax.ws.rs.DELETE; import javax.ws.rs.GET; @@ -27,30 +23,17 @@ import javax.ws.rs.core.FeatureContext; import javax.ws.rs.ext.Provider; +import io.quarkus.arc.Unremovable; + @Provider -@ApplicationScoped +@Unremovable public class SignedRequestFeature implements DynamicFeature { - final static Logger logger = Logger.getLogger("org.gameontext.signed"); - - final static void writeLog(Level level, Object source, String message, Object... args) { - if (logger.isLoggable(level)) { - logger.logp(level, source.getClass().getName(), "", message, args); - } - } - - final static void writeLog(Level level, Object source, String message, Throwable thrown) { - if (logger.isLoggable(level)) { - logger.logp(level, source.getClass().getName(), "", message, thrown); - } - } - SignedRequestSecretProvider playerClient; SignedRequestTimedCache timedCache; public SignedRequestFeature() { - // TODO: Bug in Liberty: @Inject does not work (jax-rs creates its own instance) - // work-around is to lookup the CDI beans directly + //provider/dynamicfeature isn't a cdi target, so cannot inject beans here, have to lookup programmatically playerClient = CDI.current().select(SignedRequestSecretProvider.class).get(); timedCache = CDI.current().select(SignedRequestTimedCache.class).get(); } @@ -58,8 +41,9 @@ public SignedRequestFeature() { @Override public void configure(ResourceInfo resourceInfo, FeatureContext context) { SignedRequest sr = resourceInfo.getResourceMethod().getAnnotation(SignedRequest.class); - if ( sr == null ) + if ( sr == null ){ return; + } context.register(new SignedContainerRequestFilter(playerClient, timedCache)); diff --git a/src/main/java/org/gameontext/signed/SignedRequestTimedCache.java b/src/main/java/org/gameontext/signed/SignedRequestTimedCache.java index ccc4025..1413002 100644 --- a/src/main/java/org/gameontext/signed/SignedRequestTimedCache.java +++ b/src/main/java/org/gameontext/signed/SignedRequestTimedCache.java @@ -21,15 +21,13 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; -import javax.annotation.Resource; -import javax.enterprise.concurrent.ManagedExecutorService; import javax.enterprise.context.ApplicationScoped; -@ApplicationScoped -public class SignedRequestTimedCache implements Runnable { +import io.quarkus.arc.Unremovable; - @Resource - ManagedExecutorService managedExecutorService; +@ApplicationScoped +@Unremovable +public class SignedRequestTimedCache { /** number of requests before a cleanup is triggered */ final static int TRIGGER_CLEANUP_DEPTH = 1000; @@ -43,7 +41,16 @@ public boolean isDuplicate(String hmac, Duration expiresIn) { // if the count is over or above the cutoff point, try to clean up expired sessions // avoid using size() on concurrent maps. if ( count >= TRIGGER_CLEANUP_DEPTH && triggerCount.compareAndSet(count, 0) ) { - managedExecutorService.execute(this); + SignedLogger.writeLog(Level.INFO,this,"Clearing expired hmacs"); + for ( Entry request : requests.entrySet() ) { + if ( request.getValue().hasExpired() ) { + requests.remove(request.getKey()); + } else { + // ConcurrentSkipListMap keeps them in sorted order by time + // stop as soon as we find a not expired one. + break; + } + } } TimestampedKey t = new TimestampedKey(hmac, expiresIn); @@ -55,18 +62,4 @@ public boolean isDuplicate(String hmac, Duration expiresIn) { } } - @Override - public void run() { - SignedRequestFeature.writeLog(Level.INFO,this,"Clearing expired hmacs"); - - for ( Entry request : requests.entrySet() ) { - if ( request.getValue().hasExpired() ) { - requests.remove(request.getKey()); - } else { - // ConcurrentSkipListMap keeps them in sorted order by time - // stop as soon as we find a not expired one. - break; - } - } - } } diff --git a/src/main/java/org/gameontext/signed/SignedWriterInterceptor.java b/src/main/java/org/gameontext/signed/SignedWriterInterceptor.java index ebd6501..ea63df4 100644 --- a/src/main/java/org/gameontext/signed/SignedWriterInterceptor.java +++ b/src/main/java/org/gameontext/signed/SignedWriterInterceptor.java @@ -60,7 +60,7 @@ public void aroundWriteTo(WriterInterceptorContext context) throws IOException, hmac.generateBodyHash(headers, body) .signRequest(headers); - SignedRequestFeature.writeLog(Level.FINEST, this, "WRITER INTERCEPTOR: {0}", headers); + SignedLogger.writeLog(Level.FINEST, this, "WRITER INTERCEPTOR: {0}", headers); } finally { // Write the response old.write(body);