From c2e66bceb34ca1c3f9989dd2c63546ff0c010d99 Mon Sep 17 00:00:00 2001 From: Ruud Senden <8635138+rsenden@users.noreply.github.com> Date: Fri, 26 Jul 2024 12:00:28 +0200 Subject: [PATCH] chore: Update SSC/SC-SAST/SC-DAST session management fix: When authenticating with an SSC authentication token, the SSC, SC-SAST & SC-DAST session login commands will now validate whether the given token is a valid token fix: When authenticating with an SSC authentication token, the SSC, SC-SAST & SC-DAST session commands will now display token expiration date (requires SSC 24.2+) --- .../helper/SCDastSessionDescriptor.java | 40 ++++++++++++------- .../helper/SCSastSessionDescriptor.java | 40 ++++++++++++------- .../session/helper/SSCSessionDescriptor.java | 40 ++++++++++++------- ....java => SSCTokenGetOrCreateResponse.java} | 4 +- .../access_control/helper/SSCTokenHelper.java | 26 ++++++++++++ 5 files changed, 103 insertions(+), 47 deletions(-) rename fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/helper/{SSCTokenCreateResponse.java => SSCTokenGetOrCreateResponse.java} (92%) diff --git a/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/session/helper/SCDastSessionDescriptor.java b/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/session/helper/SCDastSessionDescriptor.java index a936c23ed6..05408a4770 100644 --- a/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/session/helper/SCDastSessionDescriptor.java +++ b/fcli-core/fcli-sc-dast/src/main/java/com/fortify/cli/sc_dast/_common/session/helper/SCDastSessionDescriptor.java @@ -34,9 +34,9 @@ import com.fortify.cli.ssc._common.session.helper.ISSCCredentialsConfig; import com.fortify.cli.ssc._common.session.helper.ISSCUserCredentialsConfig; import com.fortify.cli.ssc.access_control.helper.SSCTokenCreateRequest; -import com.fortify.cli.ssc.access_control.helper.SSCTokenCreateResponse; +import com.fortify.cli.ssc.access_control.helper.SSCTokenGetOrCreateResponse; import com.fortify.cli.ssc.access_control.helper.SSCTokenHelper; -import com.fortify.cli.ssc.access_control.helper.SSCTokenCreateResponse.SSCTokenData; +import com.fortify.cli.ssc.access_control.helper.SSCTokenGetOrCreateResponse.SSCTokenData; import kong.unirest.UnirestInstance; import lombok.Data; @@ -49,7 +49,7 @@ public class SCDastSessionDescriptor extends AbstractSessionDescriptor { @JsonDeserialize(as = UrlConfig.class) private IUrlConfig sscUrlConfig; @JsonDeserialize(as = UrlConfig.class) private IUrlConfig scDastUrlConfig; private char[] predefinedToken; - private SSCTokenCreateResponse cachedTokenResponse; + private SSCTokenGetOrCreateResponse cachedTokenResponse; public SCDastSessionDescriptor(IUrlConfig sscUrlConfig, ISSCCredentialsConfig credentialsConfig) { this(sscUrlConfig, null, credentialsConfig); @@ -58,7 +58,7 @@ public SCDastSessionDescriptor(IUrlConfig sscUrlConfig, ISSCCredentialsConfig cr public SCDastSessionDescriptor(IUrlConfig sscUrlConfig, IUrlConfig scDastUrlConfig, ISSCCredentialsConfig credentialsConfig) { this.sscUrlConfig = sscUrlConfig; this.predefinedToken = credentialsConfig.getPredefinedToken(); - this.cachedTokenResponse = generateToken(sscUrlConfig, credentialsConfig); + this.cachedTokenResponse = getOrGenerateToken(sscUrlConfig, credentialsConfig); char[] activeToken = getActiveToken(); this.scDastUrlConfig = activeToken==null ? null : buildScDastUrlConfig(sscUrlConfig, scDastUrlConfig, activeToken); } @@ -106,17 +106,27 @@ public String getType() { } @JsonIgnore - protected SSCTokenCreateResponse generateToken(IUrlConfig urlConfig, ISSCCredentialsConfig credentialsConfig) { - if ( credentialsConfig.getPredefinedToken()==null ) { - ISSCUserCredentialsConfig uc = credentialsConfig.getUserCredentialsConfig(); - if ( uc!=null && StringUtils.isNotBlank(uc.getUser()) && uc.getPassword()!=null ) { - SSCTokenCreateRequest tokenCreateRequest = SSCTokenCreateRequest.builder() - .description("Auto-generated by fcli session login command") - .terminalDate(getExpiresAt(uc.getExpiresAt())) - .type("CIToken") - .build(); - return SSCTokenHelper.createToken(urlConfig, uc, tokenCreateRequest, SSCTokenCreateResponse.class); - } + protected SSCTokenGetOrCreateResponse getOrGenerateToken(IUrlConfig urlConfig, ISSCCredentialsConfig credentialsConfig) { + return credentialsConfig.getPredefinedToken()==null + ? generateToken(urlConfig, credentialsConfig) + : getToken(urlConfig, credentialsConfig); + } + + @JsonIgnore + protected SSCTokenGetOrCreateResponse getToken(IUrlConfig urlConfig, ISSCCredentialsConfig credentialsConfig) { + return SSCTokenHelper.getTokenData(urlConfig, credentialsConfig.getPredefinedToken()); + } + + @JsonIgnore + protected SSCTokenGetOrCreateResponse generateToken(IUrlConfig urlConfig, ISSCCredentialsConfig credentialsConfig) { + ISSCUserCredentialsConfig uc = credentialsConfig.getUserCredentialsConfig(); + if ( uc!=null && StringUtils.isNotBlank(uc.getUser()) && uc.getPassword()!=null ) { + SSCTokenCreateRequest tokenCreateRequest = SSCTokenCreateRequest.builder() + .description("Auto-generated by fcli session login command") + .terminalDate(getExpiresAt(uc.getExpiresAt())) + .type("CIToken") + .build(); + return SSCTokenHelper.createToken(urlConfig, uc, tokenCreateRequest, SSCTokenGetOrCreateResponse.class); } return null; } diff --git a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/session/helper/SCSastSessionDescriptor.java b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/session/helper/SCSastSessionDescriptor.java index 6551f2a985..aa5f9060cd 100644 --- a/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/session/helper/SCSastSessionDescriptor.java +++ b/fcli-core/fcli-sc-sast/src/main/java/com/fortify/cli/sc_sast/_common/session/helper/SCSastSessionDescriptor.java @@ -33,9 +33,9 @@ import com.fortify.cli.ssc._common.session.helper.ISSCCredentialsConfig; import com.fortify.cli.ssc._common.session.helper.ISSCUserCredentialsConfig; import com.fortify.cli.ssc.access_control.helper.SSCTokenCreateRequest; -import com.fortify.cli.ssc.access_control.helper.SSCTokenCreateResponse; +import com.fortify.cli.ssc.access_control.helper.SSCTokenGetOrCreateResponse; import com.fortify.cli.ssc.access_control.helper.SSCTokenHelper; -import com.fortify.cli.ssc.access_control.helper.SSCTokenCreateResponse.SSCTokenData; +import com.fortify.cli.ssc.access_control.helper.SSCTokenGetOrCreateResponse.SSCTokenData; import kong.unirest.UnirestInstance; import lombok.Data; @@ -51,7 +51,7 @@ public class SCSastSessionDescriptor extends AbstractSessionDescriptor { @JsonDeserialize(as = UrlConfig.class) private IUrlConfig scSastUrlConfig; @Getter private char[] scSastClientAuthToken; private char[] predefinedSscToken; - private SSCTokenCreateResponse cachedSscTokenResponse; + private SSCTokenGetOrCreateResponse cachedSscTokenResponse; public SCSastSessionDescriptor(IUrlConfig sscUrlConfig, ISSCCredentialsConfig credentialsConfig, char[] scSastClientAuthToken) { this(sscUrlConfig, null, credentialsConfig, scSastClientAuthToken); @@ -61,7 +61,7 @@ public SCSastSessionDescriptor(IUrlConfig sscUrlConfig, IUrlConfig scSastUrlConf this.sscUrlConfig = sscUrlConfig; this.predefinedSscToken = credentialsConfig.getPredefinedToken(); this.scSastClientAuthToken = scSastClientAuthToken; - this.cachedSscTokenResponse = generateToken(sscUrlConfig, credentialsConfig); + this.cachedSscTokenResponse = getOrGenerateToken(sscUrlConfig, credentialsConfig); char[] activeToken = getActiveSSCToken(); this.scSastUrlConfig = activeToken==null ? null : buildScSastUrlConfig(sscUrlConfig, scSastUrlConfig, activeToken); } @@ -110,17 +110,27 @@ public String getType() { } @JsonIgnore - protected SSCTokenCreateResponse generateToken(IUrlConfig urlConfig, ISSCCredentialsConfig credentialsConfig) { - if ( credentialsConfig.getPredefinedToken()==null ) { - ISSCUserCredentialsConfig uc = credentialsConfig.getUserCredentialsConfig(); - if ( uc!=null && StringUtils.isNotBlank(uc.getUser()) && uc.getPassword()!=null ) { - SSCTokenCreateRequest tokenCreateRequest = SSCTokenCreateRequest.builder() - .description("Auto-generated by fcli session login command") - .terminalDate(getExpiresAt(uc.getExpiresAt())) - .type("UnifiedLoginToken") - .build(); - return SSCTokenHelper.createToken(urlConfig, uc, tokenCreateRequest, SSCTokenCreateResponse.class); - } + protected SSCTokenGetOrCreateResponse getOrGenerateToken(IUrlConfig urlConfig, ISSCCredentialsConfig credentialsConfig) { + return credentialsConfig.getPredefinedToken()==null + ? generateToken(urlConfig, credentialsConfig) + : getToken(urlConfig, credentialsConfig); + } + + @JsonIgnore + protected SSCTokenGetOrCreateResponse getToken(IUrlConfig urlConfig, ISSCCredentialsConfig credentialsConfig) { + return SSCTokenHelper.getTokenData(urlConfig, credentialsConfig.getPredefinedToken()); + } + + @JsonIgnore + protected SSCTokenGetOrCreateResponse generateToken(IUrlConfig urlConfig, ISSCCredentialsConfig credentialsConfig) { + ISSCUserCredentialsConfig uc = credentialsConfig.getUserCredentialsConfig(); + if ( uc!=null && StringUtils.isNotBlank(uc.getUser()) && uc.getPassword()!=null ) { + SSCTokenCreateRequest tokenCreateRequest = SSCTokenCreateRequest.builder() + .description("Auto-generated by fcli session login command") + .terminalDate(getExpiresAt(uc.getExpiresAt())) + .type("UnifiedLoginToken") + .build(); + return SSCTokenHelper.createToken(urlConfig, uc, tokenCreateRequest, SSCTokenGetOrCreateResponse.class); } return null; } diff --git a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/session/helper/SSCSessionDescriptor.java b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/session/helper/SSCSessionDescriptor.java index a4ba8b7eb8..4d31efdbc4 100644 --- a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/session/helper/SSCSessionDescriptor.java +++ b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/_common/session/helper/SSCSessionDescriptor.java @@ -23,8 +23,8 @@ import com.fortify.cli.common.session.helper.SessionSummary; import com.fortify.cli.common.util.StringUtils; import com.fortify.cli.ssc.access_control.helper.SSCTokenCreateRequest; -import com.fortify.cli.ssc.access_control.helper.SSCTokenCreateResponse; -import com.fortify.cli.ssc.access_control.helper.SSCTokenCreateResponse.SSCTokenData; +import com.fortify.cli.ssc.access_control.helper.SSCTokenGetOrCreateResponse; +import com.fortify.cli.ssc.access_control.helper.SSCTokenGetOrCreateResponse.SSCTokenData; import com.fortify.cli.ssc.access_control.helper.SSCTokenHelper; import lombok.Data; @@ -35,12 +35,12 @@ @Reflectable @NoArgsConstructor public class SSCSessionDescriptor extends AbstractSessionDescriptorWithSingleUrlConfig { private char[] predefinedToken; - private SSCTokenCreateResponse cachedTokenResponse; + private SSCTokenGetOrCreateResponse cachedTokenResponse; public SSCSessionDescriptor(IUrlConfig urlConfig, ISSCCredentialsConfig credentialsConfig) { super(urlConfig); this.predefinedToken = credentialsConfig.getPredefinedToken(); - this.cachedTokenResponse = generateToken(urlConfig, credentialsConfig); + this.cachedTokenResponse = getOrGenerateToken(urlConfig, credentialsConfig); } @JsonIgnore @@ -74,17 +74,27 @@ public Date getExpiryDate() { } @JsonIgnore - protected SSCTokenCreateResponse generateToken(IUrlConfig urlConfig, ISSCCredentialsConfig credentialsConfig) { - if ( credentialsConfig.getPredefinedToken()==null ) { - ISSCUserCredentialsConfig uc = credentialsConfig.getUserCredentialsConfig(); - if ( uc!=null && StringUtils.isNotBlank(uc.getUser()) && uc.getPassword()!=null ) { - SSCTokenCreateRequest tokenCreateRequest = SSCTokenCreateRequest.builder() - .description("Auto-generated by fcli session login command") - .terminalDate(uc.getExpiresAt()) - .type("UnifiedLoginToken") - .build(); - return SSCTokenHelper.createToken(urlConfig, uc, tokenCreateRequest, SSCTokenCreateResponse.class); - } + protected SSCTokenGetOrCreateResponse getOrGenerateToken(IUrlConfig urlConfig, ISSCCredentialsConfig credentialsConfig) { + return credentialsConfig.getPredefinedToken()==null + ? generateToken(urlConfig, credentialsConfig) + : getToken(urlConfig, credentialsConfig); + } + + @JsonIgnore + protected SSCTokenGetOrCreateResponse getToken(IUrlConfig urlConfig, ISSCCredentialsConfig credentialsConfig) { + return SSCTokenHelper.getTokenData(urlConfig, credentialsConfig.getPredefinedToken()); + } + + @JsonIgnore + protected SSCTokenGetOrCreateResponse generateToken(IUrlConfig urlConfig, ISSCCredentialsConfig credentialsConfig) { + ISSCUserCredentialsConfig uc = credentialsConfig.getUserCredentialsConfig(); + if ( uc!=null && StringUtils.isNotBlank(uc.getUser()) && uc.getPassword()!=null ) { + SSCTokenCreateRequest tokenCreateRequest = SSCTokenCreateRequest.builder() + .description("Auto-generated by fcli session login command") + .terminalDate(uc.getExpiresAt()) + .type("UnifiedLoginToken") + .build(); + return SSCTokenHelper.createToken(urlConfig, uc, tokenCreateRequest, SSCTokenGetOrCreateResponse.class); } return null; } diff --git a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/helper/SSCTokenCreateResponse.java b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/helper/SSCTokenGetOrCreateResponse.java similarity index 92% rename from fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/helper/SSCTokenCreateResponse.java rename to fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/helper/SSCTokenGetOrCreateResponse.java index ea6fa1b765..68ce9d2cdf 100644 --- a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/helper/SSCTokenCreateResponse.java +++ b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/helper/SSCTokenGetOrCreateResponse.java @@ -23,8 +23,8 @@ @Data @Reflectable @NoArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) -public final class SSCTokenCreateResponse { - private SSCTokenCreateResponse.SSCTokenData data; +public final class SSCTokenGetOrCreateResponse { + private SSCTokenGetOrCreateResponse.SSCTokenData data; @Data @Reflectable @NoArgsConstructor public static final class SSCTokenData { diff --git a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/helper/SSCTokenHelper.java b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/helper/SSCTokenHelper.java index fb26ad1825..d2ff459af9 100644 --- a/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/helper/SSCTokenHelper.java +++ b/fcli-core/fcli-ssc/src/main/java/com/fortify/cli/ssc/access_control/helper/SSCTokenHelper.java @@ -26,6 +26,7 @@ import com.fortify.cli.common.http.proxy.helper.ProxyHelper; import com.fortify.cli.common.json.JsonHelper; import com.fortify.cli.common.rest.unirest.GenericUnirestFactory; +import com.fortify.cli.common.rest.unirest.UnexpectedHttpResponseException; import com.fortify.cli.common.rest.unirest.config.IUrlConfig; import com.fortify.cli.common.rest.unirest.config.IUserCredentialsConfig; import com.fortify.cli.common.rest.unirest.config.UnirestBasicAuthConfigurer; @@ -88,6 +89,12 @@ public static final T createToken(IUrlConfig urlConfig, IUserCredentialsConf } } + public static final SSCTokenGetOrCreateResponse getTokenData(IUrlConfig urlConfig, char[] token) { + try ( var unirest = GenericUnirestFactory.createUnirestInstance() ) { + return getTokenData(unirest, urlConfig, token); + } + } + public static final R run(IUrlConfig urlConfig, char[] activeToken, Function f) { try ( var unirest = GenericUnirestFactory.createUnirestInstance() ) { configureUnirest(unirest, urlConfig, activeToken); @@ -136,6 +143,25 @@ private static final T createToken(UnirestInstance unirest, IUrlConfig urlCo .getBody(); } + private static SSCTokenGetOrCreateResponse getTokenData(UnirestInstance unirest, IUrlConfig urlConfig, char[] token) { + configureUnirest(unirest, urlConfig, token); + try { + var result = unirest.post("/api/v1/userSession/tokenData") + .body(JsonHelper.getObjectMapper().createObjectNode()) + .asObject(SSCTokenGetOrCreateResponse.class) + .getBody(); + result.getData().setToken(token); + return result; + } catch ( UnexpectedHttpResponseException e ) { + if ( e.getStatus()==404 ) { + // Older SSC versions don't support this endpoint, so we just return null + return null; + } else { + throw e; + } + } + } + private static void configureUnirest(UnirestInstance unirest, IUrlConfig urlConfig, IUserCredentialsConfig uc) { UnirestUnexpectedHttpResponseConfigurer.configure(unirest); UnirestUrlConfigConfigurer.configure(unirest, urlConfig);