Skip to content

Commit c4dc217

Browse files
authored
fix: Fix responses of security provider including expired account (#2969)
Signed-off-by: Pavel Jareš <pavel.jares@broadcom.com>
1 parent 368145c commit c4dc217

File tree

11 files changed

+128
-32
lines changed

11 files changed

+128
-32
lines changed

gateway-service/src/main/java/org/zowe/apiml/gateway/security/config/CompoundAuthProvider.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,12 @@ private void warnForDummyProvider(String defaultProviderName) {
5858
}
5959

6060
private AuthenticationProvider getConfiguredLoginAuthProvider() {
61-
return authProvidersMap.get(loginProvider.getAuthProviderBeanName());
61+
String providerBeanName = loginProvider.getAuthProviderBeanName();
62+
AuthenticationProvider authenticationProvider = authProvidersMap.get(providerBeanName);
63+
if (authenticationProvider == null) {
64+
log.warn("Login provider {} is not available.", providerBeanName);
65+
}
66+
return authenticationProvider;
6267
}
6368

6469
public synchronized String getLoginAuthProviderName() {
@@ -95,7 +100,10 @@ public synchronized void setLoginAuthProvider(String provider) {
95100
@Override
96101
public Authentication authenticate(Authentication authentication) {
97102
AuthenticationProvider configuredLoginAuthProvider = getConfiguredLoginAuthProvider();
98-
return configuredLoginAuthProvider.authenticate(authentication);
103+
if (configuredLoginAuthProvider != null) {
104+
return configuredLoginAuthProvider.authenticate(authentication);
105+
}
106+
return null;
99107
}
100108

101109
/**
@@ -121,6 +129,9 @@ public Authentication authenticate(Authentication authentication) {
121129
@Override
122130
public boolean supports(Class<?> authentication) {
123131
AuthenticationProvider configuredLoginAuthProvider = getConfiguredLoginAuthProvider();
124-
return configuredLoginAuthProvider.supports(authentication);
132+
if (configuredLoginAuthProvider != null) {
133+
return configuredLoginAuthProvider.supports(authentication);
134+
}
135+
return false;
125136
}
126137
}

gateway-service/src/main/java/org/zowe/apiml/gateway/security/config/NewSecurityConfiguration.java

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
2929
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
3030
import org.springframework.security.config.http.SessionCreationPolicy;
31+
import org.springframework.security.core.userdetails.User;
32+
import org.springframework.security.core.userdetails.UserDetailsService;
3133
import org.springframework.security.web.SecurityFilterChain;
3234
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
3335
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@@ -41,8 +43,8 @@
4143
import org.zowe.apiml.gateway.controllers.CacheServiceController;
4244
import org.zowe.apiml.gateway.controllers.SafResourceAccessController;
4345
import org.zowe.apiml.gateway.error.controllers.InternalServerErrorController;
44-
import org.zowe.apiml.gateway.security.login.SuccessfulAccessTokenHandler;
4546
import org.zowe.apiml.gateway.security.login.FailedAccessTokenHandler;
47+
import org.zowe.apiml.gateway.security.login.SuccessfulAccessTokenHandler;
4648
import org.zowe.apiml.gateway.security.login.x509.X509AuthenticationProvider;
4749
import org.zowe.apiml.gateway.security.query.QueryFilter;
4850
import org.zowe.apiml.gateway.security.query.SuccessfulQueryHandler;
@@ -63,6 +65,7 @@
6365
import org.zowe.apiml.security.common.handler.FailedAuthenticationHandler;
6466
import org.zowe.apiml.security.common.login.*;
6567

68+
import java.util.Collections;
6669
import java.util.Set;
6770

6871
/**
@@ -132,7 +135,7 @@ public SecurityFilterChain authenticationFunctionalityFilterChain(HttpSecurity h
132135
.anyRequest().permitAll()
133136
.and()
134137

135-
.x509()
138+
.x509().userDetailsService(x509UserDetailsService())
136139

137140
.and()
138141
.logout()
@@ -204,7 +207,7 @@ public SecurityFilterChain accessTokenFilterChain(HttpSecurity http) throws Exce
204207
.authorizeRequests()
205208
.anyRequest().permitAll()
206209
.and()
207-
.x509()
210+
.x509().userDetailsService(x509UserDetailsService())
208211
.and()
209212
.authenticationProvider(compoundAuthProvider) // for authenticating credentials
210213
.authenticationProvider(tokenAuthenticationProvider)
@@ -259,7 +262,7 @@ public SecurityFilterChain authProtectedEndpointsFilterChain(HttpSecurity http)
259262
.authorizeRequests()
260263
.anyRequest().authenticated()
261264
.and()
262-
.x509()
265+
.x509().userDetailsService(x509UserDetailsService())
263266
.and()
264267
.authenticationProvider(compoundAuthProvider) // for authenticating credentials
265268
.apply(new CustomSecurityFilters());
@@ -273,23 +276,24 @@ public void configure(HttpSecurity http) {
273276
.addFilterBefore(loginFilter(http), org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter.class)
274277
.addFilterAfter(x509AuthenticationFilter(), org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter.class);
275278
}
276-
}
277279

278-
private NonCompulsoryAuthenticationProcessingFilter loginFilter(HttpSecurity http) {
279-
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
280-
return new BasicAuthFilter("/**",
281-
handlerInitializer.getAuthenticationFailureHandler(),
282-
securityObjectMapper,
283-
authenticationManager,
284-
handlerInitializer.getResourceAccessExceptionHandler());
285-
}
280+
private NonCompulsoryAuthenticationProcessingFilter loginFilter(HttpSecurity http) {
281+
AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class);
282+
return new BasicAuthFilter("/**",
283+
handlerInitializer.getAuthenticationFailureHandler(),
284+
securityObjectMapper,
285+
authenticationManager,
286+
handlerInitializer.getResourceAccessExceptionHandler());
287+
}
286288

289+
private X509AuthenticationFilter x509AuthenticationFilter() {
290+
return new X509AuthAwareFilter("/**",
291+
handlerInitializer.getAuthenticationFailureHandler(),
292+
x509AuthenticationProvider);
293+
}
287294

288-
private X509AuthenticationFilter x509AuthenticationFilter() {
289-
return new X509AuthAwareFilter("/**",
290-
handlerInitializer.getAuthenticationFailureHandler(),
291-
x509AuthenticationProvider);
292295
}
296+
293297
}
294298

295299

@@ -498,7 +502,7 @@ public SecurityFilterChain certificateOrAuthEndpointsFilterChain(HttpSecurity ht
498502
// filter out API ML certificate
499503
.addFilterBefore(reversedCategorizeCertFilter(), org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter.class);
500504
} else {
501-
http.x509(); // default x509 filter, authenticates trusted cert
505+
http.x509().userDetailsService(x509UserDetailsService()); // default x509 filter, authenticates trusted cert
502506
}
503507

504508
return http.authenticationProvider(compoundAuthProvider) // for authenticating credentials
@@ -633,4 +637,9 @@ protected HttpSecurity baseConfigure(HttpSecurity http) throws Exception {
633637
.exceptionHandling().authenticationEntryPoint(handlerInitializer.getBasicAuthUnauthorizedHandler())
634638
.and();
635639
}
640+
641+
private UserDetailsService x509UserDetailsService() {
642+
return username -> new User(username, "", Collections.emptyList());
643+
}
644+
636645
}

gateway-service/src/main/java/org/zowe/apiml/gateway/security/login/dummy/DummyAuthenticationProvider.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
package org.zowe.apiml.gateway.security.login.dummy;
1212

1313
import org.springframework.beans.factory.annotation.Qualifier;
14+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
1415
import org.springframework.security.authentication.AuthenticationServiceException;
1516
import org.springframework.security.authentication.BadCredentialsException;
1617
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -32,6 +33,7 @@
3233
* Allows Gateway to run without mainframe (z/OSMF service)
3334
*/
3435
@Component
36+
@ConditionalOnProperty(value = "apiml.security.auth.provider", havingValue = "dummy")
3537
public class DummyAuthenticationProvider extends DaoAuthenticationProvider {
3638
private static final String DUMMY_PROVIDER = "Dummy provider";
3739

gateway-service/src/main/java/org/zowe/apiml/gateway/security/login/dummy/InMemoryUserDetailsService.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import lombok.Data;
1515
import org.springframework.beans.factory.annotation.Autowired;
1616
import org.springframework.beans.factory.annotation.Qualifier;
17+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
1718
import org.springframework.security.core.authority.AuthorityUtils;
1819
import org.springframework.security.core.userdetails.User;
1920
import org.springframework.security.core.userdetails.UserDetails;
@@ -30,6 +31,7 @@
3031
*/
3132
@Component
3233
@Qualifier("dummyService")
34+
@ConditionalOnProperty(value = "apiml.security.auth.provider", havingValue = "dummy")
3335
public class InMemoryUserDetailsService implements UserDetailsService {
3436
private final BCryptPasswordEncoder passwordEncoder;
3537

gateway-service/src/main/java/org/zowe/apiml/gateway/security/login/saf/ZosAuthenticationProvider.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.apache.commons.lang3.ArrayUtils;
1515
import org.springframework.beans.factory.InitializingBean;
1616
import org.springframework.beans.factory.annotation.Value;
17+
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
1718
import org.springframework.security.authentication.AuthenticationProvider;
1819
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
1920
import org.springframework.security.core.Authentication;
@@ -26,6 +27,7 @@
2627

2728
@Component
2829
@Slf4j
30+
@ConditionalOnExpression("#{('${apiml.security.auth.provider:zosmf}' == 'zosmf') or ('${apiml.security.auth.provider:zosmf}' == 'dummy') or ('${apiml.security.auth.provider:zosmf}' == 'saf')}")
2931
public class ZosAuthenticationProvider implements AuthenticationProvider, InitializingBean {
3032
private PlatformUser platformUser = null;
3133

gateway-service/src/main/java/org/zowe/apiml/gateway/security/login/zosmf/ZosmfAuthenticationProvider.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import lombok.RequiredArgsConstructor;
1414
import org.apache.commons.lang3.ArrayUtils;
15+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
1516
import org.springframework.security.authentication.AuthenticationProvider;
1617
import org.springframework.security.authentication.BadCredentialsException;
1718
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -32,6 +33,7 @@
3233
*/
3334
@Component
3435
@RequiredArgsConstructor
36+
@ConditionalOnProperty(value = "apiml.security.auth.provider", havingValue = "zosmf", matchIfMissing = true)
3537
public class ZosmfAuthenticationProvider implements AuthenticationProvider {
3638

3739
private final AuthenticationService authenticationService;

gateway-service/src/main/java/org/zowe/apiml/gateway/security/service/TokenCreationService.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,14 @@
2323
import org.zowe.apiml.security.common.error.AuthenticationTokenException;
2424
import org.zowe.apiml.security.common.token.TokenAuthentication;
2525

26+
import java.util.Optional;
27+
2628
@RequiredArgsConstructor
2729
@Service
2830
@Slf4j
2931
public class TokenCreationService {
3032
private final Providers providers;
31-
private final ZosmfAuthenticationProvider zosmfAuthenticationProvider;
33+
private final Optional<ZosmfAuthenticationProvider> zosmfAuthenticationProvider;
3234
private final PassTicketService passTicketService;
3335
private final AuthenticationService authenticationService;
3436

@@ -56,7 +58,9 @@ public String createJwtTokenWithoutCredentials(String user) {
5658
log.debug("Generating PassTicket for user: {} and ZOSMF applid: {}", user, zosmfApplId);
5759
String passTicket = passTicketService.generate(user, zosmfApplId);
5860
log.debug("Generated passticket: {}", passTicket);
59-
return ((TokenAuthentication) zosmfAuthenticationProvider.authenticate(new UsernamePasswordAuthenticationToken(user, passTicket)))
61+
return ((TokenAuthentication) zosmfAuthenticationProvider
62+
.orElseThrow(() -> new IllegalStateException("The z/OSMF is not configured. The config value `apiml.security.auth.provider` should be set to `zosmf`."))
63+
.authenticate(new UsernamePasswordAuthenticationToken(user, passTicket)))
6064
.getCredentials();
6165
} catch (IRRPassTicketGenerationException e) {
6266
throw new AuthenticationTokenException("Problem with generating PassTicket");

gateway-service/src/test/java/org/zowe/apiml/gateway/security/service/TokenCreationServiceTest.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import org.zowe.apiml.security.common.error.AuthenticationTokenException;
2121
import org.zowe.apiml.security.common.token.TokenAuthentication;
2222

23+
import java.util.Optional;
24+
2325
import static org.hamcrest.MatcherAssert.assertThat;
2426
import static org.hamcrest.Matchers.is;
2527
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -48,7 +50,7 @@ void setUp() {
4850
providers = mock(Providers.class);
4951
authenticationService = mock(AuthenticationService.class);
5052

51-
underTest = new TokenCreationService(providers, zosmfAuthenticationProvider, passTicketService, authenticationService);
53+
underTest = new TokenCreationService(providers, Optional.of(zosmfAuthenticationProvider), passTicketService, authenticationService);
5254
underTest.zosmfApplId = "IZUDFLT";
5355
}
5456

integration-tests/src/test/java/org/zowe/apiml/integration/authentication/pat/AccessTokenServiceTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,12 +213,12 @@ void givenNotAuthorizedCall_thenDontAllowToRevokeTokensForUser() {
213213
given().contentType(ContentType.JSON).body(bodyContent).when()
214214
.post(VALIDATE_ENDPOINT)
215215
.then().statusCode(200);
216-
// revoke all tokens fro USERNAME
216+
// revoke all tokens for USERNAME
217217
Map<String, String> requestBody = new HashMap<>();
218218
requestBody.put("userId", SecurityUtils.USERNAME);
219219
given().contentType(ContentType.JSON).config(SslContext.clientCertApiml).body(requestBody)
220220
.when().delete(REVOKE_FOR_USER_ENDPOINT)
221-
.then().statusCode(401);
221+
.then().statusCode(403);
222222
// validate after revocation rule
223223
given().contentType(ContentType.JSON).body(bodyContent).when()
224224
.post(VALIDATE_ENDPOINT)

integration-tests/src/test/java/org/zowe/apiml/integration/authentication/providers/LoginTest.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,28 @@
1717
import io.restassured.response.Response;
1818
import io.restassured.specification.RequestSpecification;
1919
import org.apache.commons.lang3.StringUtils;
20+
import org.apache.http.HttpHeaders;
2021
import org.json.JSONObject;
21-
import org.junit.jupiter.api.*;
22+
import org.junit.jupiter.api.BeforeAll;
23+
import org.junit.jupiter.api.BeforeEach;
24+
import org.junit.jupiter.api.Nested;
2225
import org.junit.jupiter.params.ParameterizedTest;
2326
import org.junit.jupiter.params.provider.Arguments;
2427
import org.junit.jupiter.params.provider.MethodSource;
2528
import org.springframework.http.HttpStatus;
2629
import org.zowe.apiml.security.common.login.LoginRequest;
2730
import org.zowe.apiml.util.TestWithStartedInstances;
28-
import org.zowe.apiml.util.categories.*;
29-
import org.zowe.apiml.util.config.*;
31+
import org.zowe.apiml.util.categories.GeneralAuthenticationTest;
32+
import org.zowe.apiml.util.categories.SAFAuthTest;
33+
import org.zowe.apiml.util.categories.zOSMFAuthTest;
34+
import org.zowe.apiml.util.config.ConfigReader;
35+
import org.zowe.apiml.util.config.ItSslConfigFactory;
36+
import org.zowe.apiml.util.config.SslContext;
3037
import org.zowe.apiml.util.http.HttpRequestUtils;
3138

3239
import java.net.URI;
40+
import java.nio.charset.StandardCharsets;
41+
import java.util.Base64;
3342
import java.util.Optional;
3443
import java.util.stream.Stream;
3544

@@ -111,7 +120,7 @@ void givenValidCredentialsInBody(URI loginUrl) {
111120
@MethodSource("org.zowe.apiml.integration.authentication.providers.LoginTest#loginUrlsSource")
112121
void givenValidCredentialsInHeader(URI loginUrl) {
113122
String token = given()
114-
.auth().preemptive().basic(getUsername(), new String(getPassword()))
123+
.auth().preemptive().basic(getUsername(), getPassword())
115124
.contentType(JSON)
116125
.when()
117126
.post(loginUrl)
@@ -155,11 +164,11 @@ void givenInvalidCredentialsInBody(URI loginUrl) {
155164
void givenInvalidCredentialsInHeader(URI loginUrl) {
156165
String expectedMessage = "Invalid username or password for URL '" + getPath(loginUrl) + "'";
157166

158-
LoginRequest loginRequest = new LoginRequest(INVALID_USERNAME, INVALID_PASSWORD.toCharArray());
167+
String headerValue = "Basic " + Base64.getEncoder().encodeToString((INVALID_USERNAME + ":" + INVALID_PASSWORD).getBytes(StandardCharsets.UTF_8));
159168

160169
given()
161170
.contentType(JSON)
162-
.body(loginRequest)
171+
.header(HttpHeaders.AUTHORIZATION, headerValue)
163172
.when()
164173
.post(loginUrl)
165174
.then()
@@ -168,6 +177,7 @@ void givenInvalidCredentialsInHeader(URI loginUrl) {
168177
"messages.find { it.messageNumber == 'ZWEAG120E' }.messageContent", equalTo(expectedMessage)
169178
);
170179
}
180+
171181
}
172182

173183
@Nested

0 commit comments

Comments
 (0)