Skip to content

Commit

Permalink
feat: Add custom auth header to support Grafana in SSO (#2618)
Browse files Browse the repository at this point in the history
* Enable token auth via http header

Signed-off-by: at670475 <[email protected]>

* Fix

Signed-off-by: at670475 <[email protected]>

* Add it

Signed-off-by: at670475 <[email protected]>

* add env var to gh workflow

Signed-off-by: at670475 <[email protected]>

* add missing env to other wf

Signed-off-by: at670475 <[email protected]>

* fix test

Signed-off-by: at670475 <[email protected]>

* Fix cert

Signed-off-by: at670475 <[email protected]>

* fix test

Signed-off-by: at670475 <[email protected]>

* use default value for script arg

Signed-off-by: at670475 <[email protected]>

Signed-off-by: at670475 <[email protected]>
  • Loading branch information
taban03 authored Oct 14, 2022
1 parent bb29ef6 commit 9272aa0
Show file tree
Hide file tree
Showing 10 changed files with 75 additions and 5 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/containers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ jobs:
- /api-defs:/api-defs
gateway-service:
image: ghcr.io/balhar-jakub/gateway-service:${{ github.run_id }}-${{ github.run_number }}
env:
APIML_SECURITY_AUTH_CUSTOMAUTHHEADER: customHeader
mock-services:
image: ghcr.io/balhar-jakub/mock-services:${{ github.run_id }}-${{ github.run_number }}
metrics-service:
Expand Down Expand Up @@ -223,6 +225,8 @@ jobs:
- /api-defs:/api-defs
gateway-service:
image: ghcr.io/balhar-jakub/gateway-service:${{ github.run_id }}-${{ github.run_number }}
env:
APIML_SECURITY_AUTH_CUSTOMAUTHHEADER: customHeader
mock-services:
image: ghcr.io/balhar-jakub/mock-services:${{ github.run_id }}-${{ github.run_number }}
env:
Expand Down Expand Up @@ -275,6 +279,8 @@ jobs:
- /api-defs:/api-defs
gateway-service:
image: ghcr.io/balhar-jakub/gateway-service:${{ github.run_id }}-${{ github.run_number }}
env:
APIML_SECURITY_AUTH_CUSTOMAUTHHEADER: customHeader
mock-services:
image: ghcr.io/balhar-jakub/mock-services:${{ github.run_id }}-${{ github.run_number }}
env:
Expand Down Expand Up @@ -323,6 +329,8 @@ jobs:
- /api-defs:/api-defs
gateway-service:
image: ghcr.io/balhar-jakub/gateway-service:${{ github.run_id }}-${{ github.run_number }}
env:
APIML_SECURITY_AUTH_CUSTOMAUTHHEADER: customHeader
mock-services:
image: ghcr.io/balhar-jakub/mock-services:${{ github.run_id }}-${{ github.run_number }}
env:
Expand Down Expand Up @@ -372,6 +380,8 @@ jobs:
- /api-defs:/api-defs
gateway-service:
image: ghcr.io/balhar-jakub/gateway-service:${{ github.run_id }}-${{ github.run_number }}
env:
APIML_SECURITY_AUTH_CUSTOMAUTHHEADER: customHeader
mock-services:
image: ghcr.io/balhar-jakub/mock-services:${{ github.run_id }}-${{ github.run_number }}
env:
Expand Down Expand Up @@ -420,6 +430,8 @@ jobs:
- /api-defs:/api-defs
gateway-service:
image: ghcr.io/balhar-jakub/gateway-service:${{ github.run_id }}-${{ github.run_number }}
env:
APIML_SECURITY_AUTH_CUSTOMAUTHHEADER: customHeader
mock-services:
image: ghcr.io/balhar-jakub/mock-services:${{ github.run_id }}-${{ github.run_number }}
metrics-service:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public class AuthConfigurationProperties {
private AuthConfigurationProperties.CookieProperties cookieProperties;

private String provider = "zosmf";
private String customAuthHeader;

private AuthConfigurationProperties.X509Cert x509Cert;

Expand Down
1 change: 1 addition & 0 deletions config/local/gateway-service.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ apiml:
validationUrl:

auth:
customAuthHeader:
provider: dummy
zosmf:
serviceId: mockzosmf # Replace me with the correct z/OSMF service id
Expand Down
1 change: 1 addition & 0 deletions gateway-package/src/main/resources/bin/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ _BPX_JOBNAME=${ZWE_zowe_job_prefix}${GATEWAY_CODE} java \
-Dapiml.security.ssl.nonStrictVerifySslCertificatesOfServices=${nonStrictVerifySslCertificatesOfServices:-false} \
-Dapiml.security.auth.zosmf.serviceId=${ZWE_configs_apiml_security_auth_zosmf_serviceId:-zosmf} \
-Dapiml.security.auth.provider=${ZWE_configs_apiml_security_auth_provider:-zosmf} \
-Dapiml.security.auth.customAuthHeader=${ZWE_configs_apiml_security_auth_customAuthHeader:-} \
-Dapiml.security.personalAccessToken.enabled=${ZWE_configs_apiml_security_personalAccessToken_enabled:-false} \
-Dapiml.zoweManifest=${ZWE_zowe_runtimeDirectory}/manifest.json \
-Dserver.address=0.0.0.0 \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@
package org.zowe.apiml.gateway.security.service.schema;

import com.netflix.zuul.context.RequestContext;
import lombok.extern.slf4j.Slf4j;
import org.zowe.apiml.util.CookieUtil;

@Slf4j
public abstract class JwtCommand extends AuthenticationCommand {

public static final String COOKIE_HEADER = "cookie";
Expand Down Expand Up @@ -41,6 +43,16 @@ public static void removeCookie(RequestContext context, String[] names) {

}

/**
* Add HTTP header containing the JWT token to the request. The header name is defined in the configuration.
* @param context
* @param value
*/
public static void setCustomHeader(RequestContext context, String header, String value) {
log.debug("Adding HTTP header {} to the request", header);
context.addZuulRequestHeader(header, value);
}

@Override
public boolean isExpired() {
if (getExpireAt() == null) return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@

import com.netflix.appinfo.InstanceInfo;
import com.netflix.zuul.context.RequestContext;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.zowe.apiml.auth.Authentication;
import org.zowe.apiml.auth.AuthenticationScheme;
Expand All @@ -30,13 +32,21 @@
import java.util.Optional;

@Component
@AllArgsConstructor
public class ZoweJwtScheme implements IAuthenticationScheme {
@InjectApimlLogger
private final ApimlLogger logger = ApimlLogger.empty();

private AuthSourceService authSourceService;
private AuthConfigurationProperties configurationProperties;
private final AuthSourceService authSourceService;
private final AuthConfigurationProperties configurationProperties;

@Value("${apiml.security.auth.customAuthHeader:}")
private String customHeader;

@Autowired
public ZoweJwtScheme(AuthSourceService authSourceService, AuthConfigurationProperties configurationProperties) {
this.authSourceService = authSourceService;
this.configurationProperties = configurationProperties;
}

@Override
public AuthenticationScheme getScheme() {
Expand Down Expand Up @@ -90,6 +100,9 @@ public void apply(InstanceInfo instanceInfo) {
if (jwt != null) {
final RequestContext context = RequestContext.getCurrentContext();
JwtCommand.setCookie(context, configurationProperties.getCookieProperties().getCookieName(), jwt);
if (StringUtils.isNotEmpty(customHeader)) {
JwtCommand.setCustomHeader(context, customHeader, jwt);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions gateway-service/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ apiml:
clientSecret:
validationUrl:
auth:
customAuthHeader:
provider: zosmf
x509:
enabled: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,4 +224,16 @@ void whenExpiredX509AuthSource_thenCommandIsExpired() {
}
}
}

@Nested
class GivenCustomAuthHeader {
@Test
void thenAddRequestHeaderContainingToken() {
ReflectionTestUtils.setField(scheme, "customHeader", "header");
when(authSourceService.parse(authSource)).thenReturn(new ParsedTokenAuthSource("user", new Date(), new Date(), Origin.ZOSMF));
command = scheme.createCommand(null, authSource);
command.apply(null);
verify(requestContext, times(1)).addZuulRequestHeader(eq("header"), any());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import java.util.Set;

import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.core.Is.is;
import static org.zowe.apiml.util.SecurityUtils.gatewayToken;
import static org.zowe.apiml.util.SecurityUtils.personalAccessToken;
Expand Down Expand Up @@ -70,6 +70,22 @@ void givenInvalidClientCertificateInRequest() {
.statusCode(200);
}

@Nested
class GivenCustomAuthHeader {
@Test
void thenAddAuthHeader() {
String jwt = gatewayToken();
given()
.config(SslContext.tlsWithoutCert)
.header(HttpHeaders.AUTHORIZATION, "Bearer " + jwt)
.when()
.get(URL)
.then()
.body("headers.customheader", is(jwt))
.statusCode(200);
}
}

@Nested
class GivenJWTTest {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,4 @@ instanceEnv:
ZWE_configs_storage_size: 100
ZWE_zowe_verifyCertificates: true
ZWE_components_gateway_server_ssl_enabled: true
ZWE_configs_apiml_security_auth_customAuthHeader: customHeader

0 comments on commit 9272aa0

Please sign in to comment.