Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/v2.x.x' into reboot/dependencies…
Browse files Browse the repository at this point in the history
…_24_01_08
  • Loading branch information
Pablo Hernán Carle committed Jan 9, 2024
2 parents 133ecf2 + 24ba6d2 commit d5faa19
Show file tree
Hide file tree
Showing 19 changed files with 554 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,13 @@ messages:
text: "Mapping between distributed and mainframe identity failed. Reason: %s"
reason: "Mapping between distributed and mainframe identity failed."

- key: org.zowe.apiml.security.common.OIDCConfigError
number: ZWEAT610
type: ERROR
text: "Missing registry name configuration."
reason: "The registry name configuration is required to correctly map distributed user name from the OIDC access token."
action: "Make sure that 'components.gateway.apiml.security.oidc.registry' is correctly set in 'zowe.yaml'."

# Service specific messages
# 700-999

Expand Down
2 changes: 1 addition & 1 deletion apiml-tomcat-common/build.gradle
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
dependencies {
implementation libs.spring.boot.starter.web
implementation libs.tomcat.embed.el
implementation libs.zowe.attls
implementation libs.zowe.zos.utils

implementation libs.spring.aop
implementation libs.spring.beans
Expand Down
2 changes: 1 addition & 1 deletion discoverable-client/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ dependencies {
implementation libs.spring.boot.starter.validation
implementation libs.spring.boot.starter.security
implementation libs.spring.boot.starter.aop
implementation libs.zowe.attls
implementation libs.zowe.zos.utils
implementation libs.spring.cloud.commons
implementation libs.spring.cloud.starter.bootstrap
implementation libs.spring.cloud.starter.hystrix
Expand Down
2 changes: 2 additions & 0 deletions gateway-package/src/main/resources/bin/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
# - ZWE_configs_apiml_security_authorization_resourceClass
# - ZWE_configs_apiml_security_authorization_resourceNamePrefix
# - ZWE_configs_apiml_security_jwtInitializerTimeout
# - ZWE_configs_apiml_security_useInternalMapper
# - ZWE_configs_apiml_security_x509_enabled
# - ZWE_configs_apiml_security_x509_externalMapperUrl
# - ZWE_configs_apiml_security_x509_externalMapperUser
Expand Down Expand Up @@ -261,6 +262,7 @@ _BPX_JOBNAME=${ZWE_zowe_job_prefix}${GATEWAY_CODE} java \
-Dserver.internal.ssl.keyStore=${ZWE_configs_server_internal_ssl_certificate_keystore_file:-keystore/localhost/localhost-multi.keystore.p12} \
-Dapiml.security.auth.zosmf.jwtAutoconfiguration=${ZWE_configs_apiml_security_auth_zosmf_jwtAutoconfiguration:-auto} \
-Dapiml.security.jwtInitializerTimeout=${ZWE_configs_apiml_security_jwtInitializerTimeout:-5} \
-Dapiml.security.useInternalMapper=${ZWE_configs_apiml_security_useInternalMapper:-false} \
-Dapiml.security.x509.enabled=${ZWE_configs_apiml_security_x509_enabled:-false} \
-Dapiml.security.x509.externalMapperUrl=${ZWE_configs_apiml_security_x509_externalMapperUrl:-"https://${ZWE_haInstance_hostname:-localhost}:${ZWE_configs_port:-7554}/zss/api/v1/certificate/x509/map"} \
-Dapiml.security.x509.externalMapperUser=${ZWE_configs_apiml_security_x509_externalMapperUser:-${ZWE_zowe_setup_security_users_zowe:-ZWESVUSR}} \
Expand Down
1 change: 1 addition & 0 deletions gateway-service/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ dependencies {
api project(':apiml-tomcat-common')
api project(':apiml-extension-loader')

implementation libs.zowe.zos.utils
implementation libs.spring.boot.starter.webflux
implementation libs.spring.boot.starter.actuator
implementation libs.spring.boot.starter.web
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*/

package org.zowe.apiml.gateway.security.mapping;

import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.zowe.commons.usermap.CertificateResponse;
import org.zowe.commons.usermap.MapperResponse;
import org.zowe.commons.usermap.UserMapper;

/**
* Native on platform mapper. Depends on <a href="https://github.com/zowe/common-java/tree/v2.x.x/zos-utils">zos-utils</a> library
* which provides native calls to z/OS.
*/
@Slf4j
@NoArgsConstructor
@Component
@ConditionalOnProperty(value = "apiml.security.useInternalMapper", havingValue = "true")
public class NativeMapper implements NativeMapperWrapper {

final UserMapper userMapper = new UserMapper();

@Override
public CertificateResponse getUserIDForCertificate(byte[] cert) {
CertificateResponse response = userMapper.getUserIDForCertificate(cert);
log.debug("{}", response);
return response;
}

@Override
public MapperResponse getUserIDForDN(String dn, String registry) {
MapperResponse response = userMapper.getUserIDForDN(dn, registry);
log.debug("{}", response);
return response;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*/

package org.zowe.apiml.gateway.security.mapping;

import org.zowe.commons.usermap.CertificateResponse;
import org.zowe.commons.usermap.MapperResponse;

/**
* Wrapper interface around the <a href="https://github.com/zowe/common-java/blob/v2.x.x/zos-utils/src/main/java/org/zowe/commons/usermap/UserMapper.java">UserMapper</a> class
* in the zos-utils library. It wraps public native methods for better testability.
*/
public interface NativeMapperWrapper {

CertificateResponse getUserIDForCertificate(byte[] cert);

MapperResponse getUserIDForDN(String dn, String registry);
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Component;
import org.zowe.apiml.gateway.security.mapping.model.MapperResponse;
import org.zowe.apiml.gateway.security.mapping.model.OIDCRequest;
Expand All @@ -27,12 +27,13 @@
import org.zowe.apiml.product.logging.annotations.InjectApimlLogger;
import org.zowe.apiml.security.common.config.AuthConfigurationProperties;

import javax.annotation.PostConstruct;
import java.io.UnsupportedEncodingException;

import static org.zowe.apiml.gateway.security.mapping.model.MapperResponse.OIDC_FAILED_MESSAGE_KEY;

@Component("oidcMapper")
@ConditionalOnProperty(value = "apiml.security.oidc.enabled", havingValue = "true")
@ConditionalOnExpression("'${apiml.security.oidc.enabled:false}' == 'true' && '${apiml.security.useInternalMapper:false}' == 'false'")
public class OIDCExternalMapper extends ExternalMapper implements AuthenticationMapper {

@Value("${apiml.security.oidc.registry:}")
Expand All @@ -41,6 +42,16 @@ public class OIDCExternalMapper extends ExternalMapper implements Authentication
@InjectApimlLogger
private final ApimlLogger apimlLog = ApimlLogger.empty();

protected boolean isConfigError = false;

@PostConstruct
private void postConstruct() {
if (StringUtils.isEmpty(registry)) {
isConfigError = true;
apimlLog.log("org.zowe.apiml.security.common.OIDCConfigError");
}
}

public OIDCExternalMapper(@Value("${apiml.security.oidc.identityMapperUrl:}") String mapperUrl,
@Value("${apiml.security.oidc.identityMapperUser:}") String mapperUser,
CloseableHttpClient httpClientProxy,
Expand All @@ -50,17 +61,16 @@ public OIDCExternalMapper(@Value("${apiml.security.oidc.identityMapperUrl:}") St
}

public String mapToMainframeUserId(AuthSource authSource) {
if (!(authSource instanceof OIDCAuthSource)) {
apimlLog.log(MessageType.DEBUG,"The used authentication source type is {} and not OIDC", authSource.getType());
if (isConfigError) {
apimlLog.log("org.zowe.apiml.security.common.OIDCConfigError");
return null;
}

if (StringUtils.isEmpty(registry)) {
apimlLog.log(OIDC_FAILED_MESSAGE_KEY,
"Missing registry name configuration. Make sure that " +
"'components.gateway.apiml.security.oidc.registry' is correctly set in 'zowe.yaml'.");
if (!(authSource instanceof OIDCAuthSource)) {
apimlLog.log(MessageType.DEBUG,"The used authentication source type is {} and not OIDC", authSource.getType());
return null;
}

final String distributedId = ((OIDCAuthSource) authSource).getDistributedId();
if (StringUtils.isEmpty(distributedId)) {
apimlLog.log(OIDC_FAILED_MESSAGE_KEY,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*/

package org.zowe.apiml.gateway.security.mapping;

import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.stereotype.Component;
import org.zowe.apiml.gateway.security.service.schema.source.AuthSource;
import org.zowe.apiml.gateway.security.service.schema.source.OIDCAuthSource;
import org.zowe.apiml.message.core.MessageType;
import org.zowe.apiml.message.log.ApimlLogger;
import org.zowe.apiml.product.logging.annotations.InjectApimlLogger;
import org.zowe.commons.usermap.MapperResponse;

import javax.annotation.PostConstruct;

import static org.zowe.apiml.gateway.security.mapping.model.MapperResponse.OIDC_FAILED_MESSAGE_KEY;

@RequiredArgsConstructor
@Component("oidcMapper")
@ConditionalOnExpression("'${apiml.security.oidc.enabled:false}' == 'true' && '${apiml.security.useInternalMapper:false}' == 'true'")
public class OIDCNativeMapper implements AuthenticationMapper {

private final NativeMapperWrapper nativeMapper;

@Value("${apiml.security.oidc.registry:}")
protected String registry;

@InjectApimlLogger
private final ApimlLogger apimlLog = ApimlLogger.empty();

protected boolean isConfigError = false;

@PostConstruct
private void postConstruct() {
if (StringUtils.isEmpty(registry)) {
isConfigError = true;
apimlLog.log("org.zowe.apiml.security.common.OIDCConfigError");
}
}

@Override
public String mapToMainframeUserId(AuthSource authSource) {
if (isConfigError) {
apimlLog.log("org.zowe.apiml.security.common.OIDCConfigError");
return null;
}

if (!(authSource instanceof OIDCAuthSource)) {
apimlLog.log(MessageType.DEBUG, "The used authentication source type is {} and not OIDC", authSource.getType());
return null;
}

final String distributedId = ((OIDCAuthSource) authSource).getDistributedId();
if (StringUtils.isEmpty(distributedId)) {
apimlLog.log(OIDC_FAILED_MESSAGE_KEY,
"OIDC token is missing the distributed ID. Make sure your distributed identity provider is" +
" properly configured.");
return null;
}

MapperResponse response = nativeMapper.getUserIDForDN(distributedId, registry);
if (response.getRc() == 0 && StringUtils.isNotEmpty(response.getUserId())) {
return response.getUserId();
}

return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
* This mapper will be executed when ZSS is not used
*/
@Component("x509Mapper")
@ConditionalOnExpression("T(org.springframework.util.StringUtils).isEmpty('${apiml.security.x509.externalMapperUrl}')"
@ConditionalOnExpression(
"T(org.apache.commons.lang3.StringUtils).isEmpty('${apiml.security.x509.externalMapperUrl:}') && '${apiml.security.useInternalMapper:false}' == 'false'"
)
public class X509CommonNameUserMapper implements AuthenticationMapper {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@

@Slf4j
@Component("x509Mapper")
@ConditionalOnExpression("!T(org.springframework.util.StringUtils).isEmpty('${apiml.security.x509.externalMapperUrl}')"
@ConditionalOnExpression(
"T(org.apache.commons.lang3.StringUtils).isNotEmpty('${apiml.security.x509.externalMapperUrl:}') && '${apiml.security.useInternalMapper:false}' == 'false'"
)
public class X509ExternalMapper extends ExternalMapper implements AuthenticationMapper {

Expand All @@ -55,15 +56,21 @@ public X509ExternalMapper(@Value("${apiml.security.x509.externalMapperUrl:}") St
public String mapToMainframeUserId(AuthSource authSource) {
if (authSource instanceof X509AuthSource) {
X509Certificate certificate = (X509Certificate) authSource.getRawSource();
try {
HttpEntity payload = new ByteArrayEntity(certificate.getEncoded());
MapperResponse mapperResponse = callExternalMapper(payload);
if (mapperResponse != null) {
return mapperResponse.getUserId().trim();
if (certificate != null) {
try {
HttpEntity payload = new ByteArrayEntity(certificate.getEncoded());
MapperResponse mapperResponse = callExternalMapper(payload);
if (mapperResponse != null) {
return mapperResponse.getUserId().trim();
}
} catch (CertificateEncodingException e) {
log.error("Can`t get encoded data from certificate", e);
}
} catch (CertificateEncodingException e) {
log.error("Can`t get encoded data from certificate", e);
} else {
log.warn("No certificate found in the authentication source.");
}
} else {
log.debug("The used authentication source type is {} and not X509", authSource.getType());
}
return null;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*/

package org.zowe.apiml.gateway.security.mapping;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import org.zowe.apiml.gateway.security.service.schema.source.AuthSource;
import org.zowe.apiml.gateway.security.service.schema.source.X509AuthSource;
import org.zowe.commons.usermap.CertificateResponse;

import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;

@Slf4j
@RequiredArgsConstructor
@Component("x509Mapper")
@ConditionalOnProperty(value = "apiml.security.useInternalMapper", havingValue = "true")
public class X509NativeMapper implements AuthenticationMapper {

private final NativeMapperWrapper nativeMapper;

@Override
public String mapToMainframeUserId(AuthSource authSource) {
if (authSource instanceof X509AuthSource) {
X509AuthSource x509AuthSource = (X509AuthSource)authSource;
X509Certificate certificate = x509AuthSource.getRawSource();
if (certificate != null) {
try {
CertificateResponse response = nativeMapper.getUserIDForCertificate(certificate.getEncoded());
if (response.getRc() == 0 && StringUtils.isNotEmpty(response.getUserId())) {
return response.getUserId();
}
} catch (CertificateEncodingException e) {
log.error("Can`t get encoded data from certificate", e);
}
} else {
log.warn("No certificate found in the authentication source.");
}
} else {
log.debug("The used authentication source type is {} and not X509", authSource.getType());
}
return null;
}
}
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 @@ -70,6 +70,7 @@ apiml:
jwtInitializerTimeout: 5
personalAccessToken:
enabled: false
useInternalMapper: false
oidc:
enabled: false
clientId:
Expand Down
Loading

0 comments on commit d5faa19

Please sign in to comment.