Skip to content

Commit 1b673a5

Browse files
Merge pull request #82 from SAP/issue/69
Provide extension points for custom JWT post-processings
2 parents 235f13c + 4557afd commit 1b673a5

File tree

5 files changed

+354
-180
lines changed

5 files changed

+354
-180
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.sap.hcp.cf.logging.servlet.dynlog;
2+
3+
import java.security.interfaces.RSAPublicKey;
4+
5+
import javax.servlet.http.HttpServletRequest;
6+
7+
public interface DynLogConfiguration {
8+
9+
String getDynLogHeaderKey();
10+
11+
RSAPublicKey getRsaPublicKey();
12+
13+
default String getDynLogHeaderValue(HttpServletRequest httpRequest) {
14+
return httpRequest.getHeader(getDynLogHeaderKey());
15+
}
16+
17+
}

cf-java-logging-support-servlet/src/main/java/com/sap/hcp/cf/logging/servlet/dynlog/DynLogEnvironment.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
import com.sap.hcp.cf.logging.common.helper.Environment;
1212

13-
public class DynLogEnvironment {
13+
public class DynLogEnvironment implements DynLogConfiguration {
1414

1515
private static final Logger LOGGER = LoggerFactory.getLogger(DynLogEnvironment.class);
1616
private final RSAPublicKey rsaPublicKey;
@@ -46,10 +46,12 @@ public DynLogEnvironment() {
4646
}
4747
}
4848

49+
@Override
4950
public RSAPublicKey getRsaPublicKey() {
5051
return rsaPublicKey;
5152
}
5253

54+
@Override
5355
public String getDynLogHeaderKey() {
5456
return dynLogHeaderKey;
5557
}
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
package com.sap.hcp.cf.logging.servlet.dynlog;
22

3+
import java.security.interfaces.RSAPublicKey;
34
import java.util.Arrays;
45
import java.util.List;
56

6-
import javax.servlet.http.HttpServletRequest;
7-
87
import org.slf4j.Logger;
98
import org.slf4j.LoggerFactory;
109
import org.slf4j.MDC;
@@ -17,44 +16,86 @@
1716
* HTTP-request-header. If this token is provided and does contain a correct
1817
* signature, valid timestamps and a log-level-value, the log-level for the
1918
* thread triggered by this request will be changed to the provided value.
19+
*
20+
* You can extend this processor to extract custom claims from the JWT. Override
21+
* {@link DynamicLogLevelProcessor#processJWT(DecodedJWT)} for this.
2022
*/
2123
public class DynamicLogLevelProcessor {
2224

2325
private final static Logger LOGGER = LoggerFactory.getLogger(DynamicLogLevelProcessor.class);
2426
private static final List<String> ALLOWED_DYNAMIC_LOGLEVELS = Arrays.asList("TRACE", "DEBUG", "INFO", "WARN",
2527
"ERROR");
2628
private final TokenDecoder tokenDecoder;
27-
private final DynLogEnvironment dynLogEnvironment;
2829

29-
public DynamicLogLevelProcessor(DynLogEnvironment dynLogEnvironment) {
30-
this.dynLogEnvironment = dynLogEnvironment;
31-
this.tokenDecoder = new TokenDecoder(dynLogEnvironment.getRsaPublicKey());
30+
/**
31+
* @deprecated Use
32+
* {@link DynamicLogLevelProcessor#DynamicLogLevelProcessor(RSAPublicKey)}
33+
* instead.
34+
* @param dynLogConfig
35+
* the {@link DynLogConfiguration} to read the public RSA key for
36+
* JWT validation from.
37+
*/
38+
@Deprecated
39+
public DynamicLogLevelProcessor(DynLogConfiguration dynLogConfig) {
40+
this(dynLogConfig.getRsaPublicKey());
41+
}
42+
43+
public DynamicLogLevelProcessor(RSAPublicKey publicJwtKey) {
44+
this.tokenDecoder = new TokenDecoder(publicJwtKey);
3245
}
3346

34-
public void copyDynamicLogLevelToMDC(HttpServletRequest httpRequest) {
35-
String logLevelToken = httpRequest.getHeader(dynLogEnvironment.getDynLogHeaderKey());
47+
/**
48+
* Decodes and validate the JWT. Configures the dynamic log levels by
49+
* setting the corresponding fields in the MDC.
50+
*
51+
* @param logLevelToken
52+
* the HTTP Header containing the JWT for dynamic log levels
53+
*/
54+
public void copyDynamicLogLevelToMDC(String logLevelToken) {
3655
if (logLevelToken == null) {
3756
return;
3857
} else {
3958
try {
4059
DecodedJWT jwt = tokenDecoder.validateAndDecodeToken(logLevelToken);
41-
String dynamicLogLevel = jwt.getClaim("level").asString();
42-
String packages = jwt.getClaim("packages").asString();
43-
if (ALLOWED_DYNAMIC_LOGLEVELS.contains(dynamicLogLevel)) {
44-
MDC.put(DynamicLogLevelHelper.MDC_DYNAMIC_LOG_LEVEL_KEY, dynamicLogLevel);
45-
MDC.put(DynamicLogLevelHelper.MDC_DYNAMIC_LOG_LEVEL_PREFIXES, packages);
46-
} else {
47-
throw new DynamicLogLevelException("Dynamic Log-Level [" + dynamicLogLevel +
48-
"] provided in header is not valid. Allowed Values are " +
49-
ALLOWED_DYNAMIC_LOGLEVELS.toString());
50-
}
51-
} catch (DynamicLogLevelException e) {
52-
LOGGER.warn("DynamicLogLevelProcessor could not write dynamic log level to MDC", e);
60+
processJWT(jwt);
61+
} catch (DynamicLogLevelException cause) {
62+
LOGGER.warn("DynamicLogLevelProcessor could not write dynamic log level to MDC", cause);
5363
}
5464
}
5565
}
5666

67+
/**
68+
* Extracts the relevant claims for dynamic log level configuration from the
69+
* decoded token. In case of faulty content, i.e. unknown log level a
70+
* {@link DynamicLogLevelException} is thrown. You can override this method
71+
* to implement own interaction with the JWT, e.g. extraction and validation
72+
* of additional claims.
73+
*
74+
* @param jwt
75+
* the decoded JWT from the HTTP header
76+
* @throws DynamicLogLevelException
77+
* if validation of JWT claims fail
78+
*/
79+
protected void processJWT(DecodedJWT jwt) throws DynamicLogLevelException {
80+
String dynamicLogLevel = jwt.getClaim("level").asString();
81+
String packages = jwt.getClaim("packages").asString();
82+
if (ALLOWED_DYNAMIC_LOGLEVELS.contains(dynamicLogLevel)) {
83+
MDC.put(DynamicLogLevelHelper.MDC_DYNAMIC_LOG_LEVEL_KEY, dynamicLogLevel);
84+
MDC.put(DynamicLogLevelHelper.MDC_DYNAMIC_LOG_LEVEL_PREFIXES, packages);
85+
} else {
86+
throw new DynamicLogLevelException("Dynamic Log-Level [" + dynamicLogLevel +
87+
"] provided in header is not valid. Allowed Values are " +
88+
ALLOWED_DYNAMIC_LOGLEVELS.toString());
89+
}
90+
}
91+
92+
/**
93+
* Resets the current dynamic log level configuration by removing the
94+
* corresponding fields from the MDC. This needs to be called to remove the
95+
* changed log level configuration.
96+
*/
5797
public void removeDynamicLogLevelFromMDC() {
5898
MDC.remove(DynamicLogLevelHelper.MDC_DYNAMIC_LOG_LEVEL_KEY);
99+
MDC.remove(DynamicLogLevelHelper.MDC_DYNAMIC_LOG_LEVEL_PREFIXES);
59100
}
60101
}

0 commit comments

Comments
 (0)