Skip to content

Commit

Permalink
feat: zowe jwt from x509 (update) (#2292)
Browse files Browse the repository at this point in the history
* feat: Enhance x509 authentication scheme to support client certificates (part 1)

move the logic which gets authentication source from request to scheme

* feat: Enhance x509 authentication scheme to support client certificates (part 2)

- validate extended key usage for X509 certificate in getAuthSourceFromRequest() method;
- use AuthSourceService in X509Scheme.

Signed-off-by: Yelyzaveta Chebanova <[email protected]>

* merge with master branch

Signed-off-by: Yelyzaveta Chebanova <[email protected]>

* feat: Enhance x509 authentication scheme to support client certificates (part 2)

-remove unnecessary usage of Serializable

Signed-off-by: Yelyzaveta Chebanova <[email protected]>

* feat: Enhance x509 authentication scheme to support client certificates (part 2)

- cleanup

Signed-off-by: Yelyzaveta Chebanova <[email protected]>

* feat: Enhance x509 authentication scheme to support client certificates (part 3)

- add "X-Zowe-Auth-Failure" headers for X509Scheme error situations

Signed-off-by: Yelyzaveta Chebanova <[email protected]>

* feat: Enhance x509 authentication scheme to support client certificates (part 3)

- add "X-Zowe-Auth-Failure" header when client certificate is missing or invalid

Signed-off-by: Yelyzaveta Chebanova <[email protected]>

* feat: Enhance x509 authentication scheme to support client certificates (part 3)

- add IT for X509Scheme

Signed-off-by: Yelyzaveta Chebanova <[email protected]>

* feat: Enhance x509 authentication scheme to support client certificates (part 3)

- store information about X509 validation error in context to set error header later

Signed-off-by: Yelyzaveta Chebanova <[email protected]>

* feat: Enhance x509 authentication scheme to support client certificates (part 3)

- resolve merge conflicts

Signed-off-by: Yelyzaveta Chebanova <[email protected]>

* feat: Enhance x509 authentication scheme to support client certificates (part 3)

- fix IT for X509 scheme

Signed-off-by: Yelyzaveta Chebanova <[email protected]>

* Add isExpired() method to ZoweJwtScheme to correctly detect expiration

Signed-off-by: Yelyzaveta Chebanova <[email protected]>

* Check for validation errors in context to propagate them into "X-Zowe-Auth-Failure" header

Signed-off-by: Yelyzaveta Chebanova <[email protected]>

* Move default expiration for X509 certificate into AuthConfigurationProperties

Signed-off-by: Yelyzaveta Chebanova <[email protected]>

* Fix merge issues

Signed-off-by: Yelyzaveta Chebanova <[email protected]>
  • Loading branch information
yelyzavetachebanova authored Apr 11, 2022
1 parent a053b00 commit c602080
Show file tree
Hide file tree
Showing 6 changed files with 184 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ public class AuthConfigurationProperties {
private String provider = "zosmf";

private AuthConfigurationProperties.PassTicket passTicket;
private AuthConfigurationProperties.X509Cert x509Cert;

private AuthConfigurationProperties.Zosmf zosmf = new AuthConfigurationProperties.Zosmf();

Expand Down Expand Up @@ -88,6 +89,11 @@ public static class PassTicket {
private Integer timeout = 540;
}

@Data
public static class X509Cert {
private Integer timeout = 15 * 60;
}

@Data
public static class Zosmf {
private String serviceId;
Expand All @@ -99,6 +105,7 @@ public AuthConfigurationProperties() {
this.cookieProperties = new AuthConfigurationProperties.CookieProperties();
this.tokenProperties = new AuthConfigurationProperties.TokenProperties();
this.passTicket = new AuthConfigurationProperties.PassTicket();
this.x509Cert = new AuthConfigurationProperties.X509Cert();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
*/
package org.zowe.apiml.gateway.security.service.schema;

import static org.zowe.apiml.gateway.security.service.schema.source.AuthSourceService.X509_DEFAULT_EXPIRATION;

import com.netflix.appinfo.InstanceInfo;
import com.netflix.zuul.context.RequestContext;
import java.util.Optional;
Expand All @@ -27,6 +25,7 @@
import org.zowe.apiml.gateway.security.service.schema.source.AuthSourceService;
import org.zowe.apiml.gateway.security.service.schema.source.X509AuthSource;
import org.zowe.apiml.message.core.MessageService;
import org.zowe.apiml.security.common.config.AuthConfigurationProperties;

/**
* This schema adds requested information about client certificate. This information is added
Expand All @@ -36,14 +35,16 @@
@Slf4j
public class X509Scheme implements IAuthenticationScheme {
private final AuthSourceService authSourceService;
private final AuthConfigurationProperties authConfigurationProperties;
private final MessageService messageService;

public static final String AUTH_FAIL_HEADER = "X-Zowe-Auth-Failure";
public static final String ALL_HEADERS = "X-Certificate-Public,X-Certificate-DistinguishedName,X-Certificate-CommonName";

public X509Scheme(@Autowired @Qualifier("x509CNAuthSourceService") AuthSourceService authSourceService, MessageService messageService) {
public X509Scheme(@Autowired @Qualifier("x509CNAuthSourceService") AuthSourceService authSourceService, MessageService messageService, AuthConfigurationProperties authConfigurationProperties) {
this.authSourceService = authSourceService;
this.messageService = messageService;
this.authConfigurationProperties = authConfigurationProperties;
}

@Override
Expand Down Expand Up @@ -76,7 +77,7 @@ public AuthenticationCommand createCommand(Authentication authentication, AuthSo
headers = authentication.getHeaders().split(",");
}

final long defaultExpirationTime = System.currentTimeMillis() + X509_DEFAULT_EXPIRATION;
final long defaultExpirationTime = System.currentTimeMillis() + authConfigurationProperties.getX509Cert().getTimeout() * 1000L;
final long expirationTime = parsedAuthSource.getExpiration() != null ? parsedAuthSource.getExpiration().getTime() : defaultExpirationTime;
final long expireAt = Math.min(defaultExpirationTime, expirationTime);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
*/
package org.zowe.apiml.gateway.security.service.schema;

import static org.zowe.apiml.gateway.security.service.schema.JwtCommand.AUTH_FAIL_HEADER;

import com.netflix.appinfo.InstanceInfo;
import com.netflix.zuul.context.RequestContext;
import lombok.AllArgsConstructor;
Expand Down Expand Up @@ -52,6 +54,14 @@ public Optional<AuthSource> getAuthSource() {

@Override
public AuthenticationCommand createCommand(Authentication authentication, AuthSource authSource) {
final RequestContext context = RequestContext.getCurrentContext();
// Check for error in context to use it in header "X-Zowe-Auth-Failure"
if (context.containsKey(AUTH_FAIL_HEADER)) {
String errorHeaderValue = context.get(AUTH_FAIL_HEADER).toString();
// this command should expire immediately after creation because it is build based on missing/incorrect authentication
return new ZoweJwtAuthCommand(System.currentTimeMillis(), null, errorHeaderValue);
}

String error = null;
String jwt = null;
AuthSource.Parsed parsedAuthSource = null;
Expand All @@ -68,15 +78,19 @@ public AuthenticationCommand createCommand(Authentication authentication, AuthSo
if (error != null) {
return new ZoweJwtAuthCommand(null, null, error);
}

final long defaultExpirationTime = System.currentTimeMillis() + configurationProperties.getTokenProperties().getExpirationInSeconds() * 1000L;
final Date expiration = parsedAuthSource == null ? null : parsedAuthSource.getExpiration();
final Long expirationTime = expiration == null ? null : expiration.getTime();
final long expirationTime = expiration != null ? expiration.getTime() : defaultExpirationTime;
final long expireAt = Math.min(defaultExpirationTime, expirationTime);

try {
jwt = authSourceService.getJWT(authSource);
} catch (UserNotMappedException | AuthenticationTokenException e) {
error = this.messageService.createMessage(e.getMessage()).mapToLogMessage();
}

return new ZoweJwtAuthCommand(expirationTime, jwt, error);
return new ZoweJwtAuthCommand(expireAt, jwt, error);
}

@lombok.Value
Expand Down Expand Up @@ -109,5 +123,12 @@ public void applyToRequest(HttpRequest request) {
JwtCommand.addErrorHeader(request, errorHeader);
}
}

@Override
public boolean isExpired() {
if (expireAt == null) return false;

return System.currentTimeMillis() > expireAt;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@
* Interface represents main methods of service which gets the source of authentication and process it.
*/
public interface AuthSourceService {
// Default expiration time for client certificate 15 min
Long X509_DEFAULT_EXPIRATION = 15L * 60 * 1000;

/**
* Core method of the interface. Gets specific source of authentication from request and defines precedence
* in case if more than one source is present.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import java.security.cert.X509Certificate;
import org.zowe.apiml.message.core.MessageService;
import org.zowe.apiml.message.yaml.YamlMessageService;
import org.zowe.apiml.security.common.config.AuthConfigurationProperties;
import org.zowe.apiml.security.common.error.InvalidCertificateException;

import static org.junit.jupiter.api.Assertions.assertEquals;
Expand All @@ -51,6 +52,7 @@ class X509SchemeTest {
HttpServletRequest request;
X509Certificate x509Certificate;
AuthSourceService authSourceService;
AuthConfigurationProperties authConfigurationProperties;
X509AuthSource authSource;
X509AuthSource.Parsed parsedSource;
X509Scheme x509Scheme;
Expand All @@ -75,7 +77,9 @@ void setup() {
parsedSource = new Parsed("commonName", new Date(), new Date(), Origin.X509, "", "distName");

authSourceService = mock(AuthSourceService.class);
x509Scheme = new X509Scheme(authSourceService, messageService);
authConfigurationProperties = mock(AuthConfigurationProperties.class);
doReturn(new AuthConfigurationProperties.X509Cert()).when(authConfigurationProperties).getX509Cert();
x509Scheme = new X509Scheme(authSourceService, messageService, authConfigurationProperties);
authentication = new Authentication(AuthenticationScheme.X509, null, null);
}

Expand Down
Loading

0 comments on commit c602080

Please sign in to comment.