Skip to content

Commit

Permalink
chore: v2 cherry pick (#3516)
Browse files Browse the repository at this point in the history
* fix: allow key exchange port configuration (#3453)

* allow key exchange port configuration

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

* explain different defaults for the port

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

* use the same default port number

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

---------

Signed-off-by: achmelo <[email protected]>
(cherry picked from commit d82322e)

* chore: Change log levels for WS and Identity Mapper and add service info (#3344)

* add info about the southbound service request for authsource

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

* add debug msg for websocket routing

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

* address pr comments

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

---------

Signed-off-by: at670475 <[email protected]>
(cherry picked from commit 0a888f8)

* fix: Respect configuration enabling JWT Token Refresh Functionality #3468 (#3474)

* Respect JWT Refresh Configuration from zowe.yaml

Signed-off-by: Jakub Balhar <[email protected]>

* Fix the default in shell.

Signed-off-by: Jakub Balhar <[email protected]>

---------

Signed-off-by: Jakub Balhar <[email protected]>
(cherry picked from commit b4146be)

* feat: include OIDC JWKSet in the gateway JWKs (#3499)

* use the same JWK format, include OIDC keys in the response

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

* cleanup, update tests

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

* integration test for local validation

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

* set default ssl factory

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

* change debug message

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

* test coverage

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

---------

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

(cherry picked from commit a588a8f)
Signed-off-by: achmelo <[email protected]>

* feat: forward valid OIDC token to southbound service in case of distributed ID is not mapped (#3497)

* forward token and message in case of missing mapping

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

* fix test

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

* add unit test

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

* small refactoring

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

* updating integration tests

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

* add test

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

* add exception to the error handler to return correct response code

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

* fix styles

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

---------

Signed-off-by: at670475 <[email protected]>
Signed-off-by: achmelo <[email protected]>
Co-authored-by: achmelo <[email protected]>
Co-authored-by: achmelo <[email protected]>
(cherry picked from commit 60777c1)

* fix: check for nullpointer exception when jwk key can't be retrieved (#3503)

* check for nullpointer ex when jwk key can't be retrieved

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

* add test

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

* address comment

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

---------

Signed-off-by: at670475 <[email protected]>
(cherry picked from commit 7c00dba)

* revert

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

* use current methods

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

* feat: Move OIDC access token from cookie to special header (#3513)

* POC

Signed-off-by: Pavel Jares <[email protected]>

* fix

Signed-off-by: Pavel Jares <[email protected]>

* replace old constructors

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

* update IT

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

* fix

Signed-off-by: Pavel Jares <[email protected]>

* update IT

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

* fix IT

Signed-off-by: Pavel Jares <[email protected]>

* exception handler for no MF ID, unit test

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

* unit tests for request modification

Signed-off-by: Pavel Jares <[email protected]>

* license

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

* minor changes

Signed-off-by: Pavel Jares <[email protected]>

* lowercase header

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

* remove import

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

* remove authorization header from httpservletrequest

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

* test no ID and invalid token

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

* ignore cookies if auth cookie only remains

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

* expect no cookie in request

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

* fix sonar

Signed-off-by: Pavel Jares <[email protected]>

---------

Signed-off-by: Pavel Jares <[email protected]>
Signed-off-by: achmelo <[email protected]>
Co-authored-by: achmelo <[email protected]>
(cherry picked from commit 6248308)

* url without default

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

* use the same jwk uri

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

* attempt to fix IT

Signed-off-by: Pavel Jares <[email protected]>

* Revert "attempt to fix IT"

This reverts commit cf35400.

* use keyLocator for JWK set

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

---------

Signed-off-by: achmelo <[email protected]>
Signed-off-by: Pavel Jares <[email protected]>
Co-authored-by: Andrea Tabone <[email protected]>
Co-authored-by: Jakub Balhar <[email protected]>
Co-authored-by: Pavel Jareš <[email protected]>
Co-authored-by: Pavel Jares <[email protected]>
  • Loading branch information
5 people authored Apr 24, 2024
1 parent c20fc42 commit c9dd4aa
Show file tree
Hide file tree
Showing 42 changed files with 949 additions and 331 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ jobs:
APIML_SECURITY_OIDC_CLIENTSECRET: ${{ secrets.OKTA_CLIENT_PASSWORD }}
APIML_SECURITY_OIDC_ENABLED: true
APIML_SECURITY_OIDC_REGISTRY: zowe.okta.com
APIML_SECURITY_OIDC_JWKS_URI: ${{ secrets.OKTA_JWK_URI }}
APIML_SECURITY_OIDC_JWKS_URI: ${{ secrets.OKTA_JWKSET_URI }}
APIML_SECURITY_OIDC_IDENTITYMAPPERUSER: APIMTST
APIML_SECURITY_OIDC_IDENTITYMAPPERURL: https://gateway-service:10010/zss/api/v1/certificate/dn
discovery-service:
Expand Down Expand Up @@ -391,7 +391,7 @@ jobs:
APIML_SECURITY_OIDC_CLIENTSECRET: ${{ secrets.OKTA_CLIENT_PASSWORD }}
APIML_SECURITY_OIDC_ENABLED: true
APIML_SECURITY_OIDC_REGISTRY: zowe.okta.com
APIML_SECURITY_OIDC_JWKS_URI: ${{ secrets.OKTA_JWK_URI }}
APIML_SECURITY_OIDC_JWKS_URI: ${{ secrets.OKTA_JWKSET_URI }}
APIML_SECURITY_OIDC_IDENTITYMAPPERUSER: APIMTST
APIML_SECURITY_OIDC_IDENTITYMAPPERURL: https://gateway-service:10010/zss/api/v1/certificate/dn
mock-services:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.zowe.apiml.message.api.ApiMessageView;
import org.zowe.apiml.message.core.MessageService;
import org.zowe.apiml.security.common.token.InvalidTokenTypeException;
import org.zowe.apiml.security.common.token.NoMainframeIdentityException;
import org.zowe.apiml.security.common.token.TokenExpireException;
import org.zowe.apiml.security.common.token.TokenFormatNotValidException;
import org.zowe.apiml.security.common.token.TokenNotProvidedException;
Expand Down Expand Up @@ -64,6 +65,8 @@ public void handleException(HttpServletRequest request, HttpServletResponse resp
handleAuthMethodNotSupported(request, response, ex);
} else if (ex instanceof TokenNotValidException) {
handleTokenNotValid(request, response, ex);
} else if (ex instanceof NoMainframeIdentityException) {
handleNoMainframeIdentity(request, response, ex);
} else if (ex instanceof TokenNotProvidedException) {
handleTokenNotProvided(request, response, ex);
} else if (ex instanceof TokenExpireException) {
Expand Down Expand Up @@ -120,6 +123,11 @@ private void handleTokenNotValid(HttpServletRequest request, HttpServletResponse
writeErrorResponse(ErrorType.TOKEN_NOT_VALID.getErrorMessageKey(), HttpStatus.UNAUTHORIZED, request, response);
}

private void handleNoMainframeIdentity(HttpServletRequest request, HttpServletResponse response, RuntimeException ex) throws ServletException {
log.debug(MESSAGE_FORMAT, HttpStatus.UNAUTHORIZED.value(), ex.getMessage());
writeErrorResponse(ErrorType.IDENTITY_MAPPING_FAILED.getErrorMessageKey(), HttpStatus.UNAUTHORIZED, request, response);
}

private void handleTokenNotProvided(HttpServletRequest request, HttpServletResponse response, RuntimeException ex) throws ServletException {
log.debug(MESSAGE_FORMAT, HttpStatus.UNAUTHORIZED.value(), ex.getMessage());
writeErrorResponse(ErrorType.TOKEN_NOT_PROVIDED.getErrorMessageKey(), HttpStatus.UNAUTHORIZED, request, response);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ public enum ErrorType {
INVALID_TOKEN_TYPE("org.zowe.apiml.security.login.invalidTokenType", "Invalid token type in response from Authentication service.", "Review your APIML authentication provider configuration and ensure your Authentication service is working."),
USER_SUSPENDED("org.zowe.apiml.security.platform.errno.EMVSSAFEXTRERR","Account Suspended", "Contact your security administrator to unsuspend your account."),
NEW_PASSWORD_INVALID("org.zowe.apiml.security.platform.errno.EMVSPASSWORD", "The new password is not valid", "Provide valid password."),
PASSWORD_EXPIRED("org.zowe.apiml.security.platform.errno.EMVSEXPIRE", "Password has expired", "Contact your security administrator to reset your password.");
PASSWORD_EXPIRED("org.zowe.apiml.security.platform.errno.EMVSEXPIRE", "Password has expired", "Contact your security administrator to reset your password."),
IDENTITY_MAPPING_FAILED("org.zowe.apiml.gateway.security.schema.x509.mappingFailed", "No user was found", "Ask your security administrator to connect your token or client certificate with your mainframe user.");

private final String errorMessageKey;
private final String defaultMessage;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* 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.security.common.token;

import lombok.Getter;
import org.springframework.security.core.AuthenticationException;

/**
* This exception is thrown in case the OIDC token is valid but distributed ID is not mapped to the mainframe ID.
*/
@Getter
public class NoMainframeIdentityException extends AuthenticationException {

private final boolean validToken;
private final String token;

public NoMainframeIdentityException(String msg) {
this(msg, null, false);
}

public NoMainframeIdentityException(String msg, String token, boolean validToken) {
super(msg);
this.token = token;
this.validToken = validToken;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,7 @@
import org.zowe.apiml.message.core.MessageService;
import org.zowe.apiml.message.yaml.YamlMessageService;
import org.zowe.apiml.security.common.auth.saf.PlatformReturned;
import org.zowe.apiml.security.common.token.InvalidTokenTypeException;
import org.zowe.apiml.security.common.token.TokenFormatNotValidException;
import org.zowe.apiml.security.common.token.TokenNotProvidedException;
import org.zowe.apiml.security.common.token.TokenNotValidException;
import org.zowe.apiml.security.common.token.*;

import jakarta.servlet.ServletException;

Expand Down Expand Up @@ -135,6 +132,20 @@ void testAuthenticationFailure_whenExceptionIsTokenNotValidException() throws IO
verify(objectMapper).writeValue(httpServletResponse.getWriter(), message.mapToView());
}

@Test
void testAuthenticationFailure_whenExceptionIsNoMainframeIdException() throws IOException, ServletException {
authExceptionHandler.handleException(
httpServletRequest,
httpServletResponse,
new NoMainframeIdentityException("ERROR"));

assertEquals(HttpStatus.UNAUTHORIZED.value(), httpServletResponse.getStatus());
assertEquals(MediaType.APPLICATION_JSON_VALUE, httpServletResponse.getContentType());

Message message = messageService.createMessage(ErrorType.IDENTITY_MAPPING_FAILED.getErrorMessageKey(), httpServletRequest.getRequestURI());
verify(objectMapper).writeValue(httpServletResponse.getWriter(), message.mapToView());
}

@Test
void testAuthenticationFailure_whenExceptionIsTokenNotProvidedException() throws IOException, ServletException {
authExceptionHandler.handleException(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* 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.security.common.token;

import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.*;

class NoMainframeIdentityExceptionTest {
@Nested
class GivenExceptionMessage {

@Test
void thenReturnMessage() {
String message = "This is an error message";
NoMainframeIdentityException exception = new NoMainframeIdentityException(message);
assertEquals(message, exception.getMessage());
}
}
}
1 change: 1 addition & 0 deletions caching-service-package/src/main/resources/bin/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ _BPX_JOBNAME=${ZWE_zowe_job_prefix}${CACHING_CODE} java \
-Dcaching.storage.vsam.name=${VSAM_FILE_NAME} \
-Djgroups.bind.address=${ZWE_haInstance_hostname:-localhost} \
-Djgroups.bind.port=${ZWE_configs_storage_infinispan_jgroups_port:-7098} \
-Djgroups.keyExchange.port=${ZWE_configs_storage_infinispan_jgroups_keyExchange_port:-7118} \
-Dcaching.storage.infinispan.persistence.dataLocation=${ZWE_configs_storage_infinispan_persistence_dataLocation:-data} \
-Dcaching.storage.infinispan.persistence.indexLocation=${ZWE_configs_storage_infinispan_persistence_indexLocation:-index} \
-Dcaching.storage.infinispan.initialHosts=${ZWE_configs_storage_infinispan_initialHosts:-localhost[7098]} \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ public class InfinispanConfig {
private String port;
@Value("${jgroups.bind.address}")
private String address;
@Value("${jgroups.keyExchange.port:7118}")
private String keyExchangePort;

@PostConstruct
void updateKeyring() {
Expand All @@ -74,6 +76,7 @@ DefaultCacheManager cacheManager(ResourceLoader resourceLoader) {
System.setProperty("jgroups.tcpping.initial_hosts", initialHosts);
System.setProperty("jgroups.bind.port", port);
System.setProperty("jgroups.bind.address", address);
System.setProperty("jgroups.keyExchange.port", keyExchangePort);
System.setProperty("server.ssl.keyStoreType", keyStoreType);
System.setProperty("server.ssl.keyStore", keyStore);
System.setProperty("server.ssl.keyStorePassword", keyStorePass);
Expand Down
2 changes: 1 addition & 1 deletion caching-service/src/main/resources/infinispan.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
keystore_type="${server.ssl.keyStoreType}"
keystore_password="${server.ssl.keyStorePassword}"
secret_key_algorithm="RSA"
port="${jgroups.keyExchange.port}"
/>
<!-- Configures ASYM_ENCRYPT -->
<!-- Uses the stack.combine and stack.position attributes to insert ASYM_ENCRYPT into the default TCP stack before pbcast.NAKACK2. -->
<!-- The use_external_key_exchange = "true" attribute configures nodes to use the `SSL_KEY_EXCHANGE` protocol for certificate authentication. -->
<ASYM_ENCRYPT asym_keylength="2048"
asym_algorithm="RSA"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
package org.zowe.apiml.cloudgatewayservice.filters;

import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
Expand Down Expand Up @@ -66,12 +67,20 @@ protected WebClient.RequestHeadersSpec<?> createRequest(ServiceInstance instance
@Override
@SuppressWarnings("squid:S2092") // the internal API cannot define generic more specifically
protected Mono<Void> processResponse(ServerWebExchange exchange, GatewayFilterChain chain, ZaasTokenResponse response) {
ServerHttpRequest request;
ServerHttpRequest request = null;
if (response.getToken() != null) {
request = exchange.getRequest().mutate().headers(headers ->
headers.add(HttpHeaders.COOKIE, new HttpCookie(response.getCookieName(), response.getToken()).toString())
).build();
} else {
if (!StringUtils.isEmpty(response.getCookieName())) {
request = exchange.getRequest().mutate().headers(headers ->
headers.add(HttpHeaders.COOKIE, new HttpCookie(response.getCookieName(), response.getToken()).toString())
).build();
}
if (!StringUtils.isEmpty(response.getHeaderName())) {
request = exchange.getRequest().mutate().headers(headers ->
headers.add(response.getHeaderName(), response.getToken())
).build();
}
}
if (request == null) {
request = updateHeadersForError(exchange, "Invalid or missing authentication");
}

Expand Down
Loading

0 comments on commit c9dd4aa

Please sign in to comment.