Skip to content
45 changes: 44 additions & 1 deletion checkstyle.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,48 @@
<module name="StaticVariableName"/>
<module name="ConstantName"/>
<module name="TypeName"/>

<module name="MultipleStringLiterals">
<property name="allowedDuplicates" value="1"/>
<property name="ignoreOccurrenceContext" value="ANNOTATION"/>
<property name="ignoreStringsRegexp" value='^""$|^"."$'/>
</module>

<module name="StringLiteralEquality"/>

<module name="MagicNumber">
<property name="ignoreNumbers" value="-1,0,1,2,3,64,200,201,204,299,400,401,403,404,500,1000,60000"/>
<property name="ignoreFieldDeclaration" value="true"/>
<property name="ignoreAnnotation" value="true"/>
</module>

<!-- Detect common hardcoded JSON field names in .get() calls -->
<module name="RegexpSinglelineJava">
<property name="format" value='\.get\("(error|message|tokens|records|fields|details|grpc_code|http_status|Body|exp|skyflow_id|privateKey|clientID|keyID|tokenURI)"\)'/>
<property name="message" value="Use Constants.JsonFieldNames or Constants.CredentialFields instead of hardcoded field names. Use IDE search-replace for: error, message, tokens, records, fields, details, grpc_code, http_status, Body, exp, skyflow_id, privateKey, clientID, keyID, tokenURI"/>
<property name="ignoreComments" value="true"/>
</module>

<!-- Detect common hardcoded JSON field names in .put() calls -->
<module name="RegexpSinglelineJava">
<property name="format" value='\.put\("(error|value|token|type|requestIndex|requestId)"\s*,'/>
<property name="message" value="Use Constants.JsonFieldNames instead of hardcoded field names. Use IDE search-replace for: error, value, token, type, requestIndex, requestId"/>
<property name="ignoreComments" value="true"/>
</module>

<!-- Detect common hardcoded JSON field names in .add() and .addProperty() calls -->
<module name="RegexpSinglelineJava">
<property name="format" value='\.(add|addProperty)\("(errors|tokens|value|token|type|error|updatedField)"\s*,'/>
<property name="message" value="Use Constants.JsonFieldNames instead of hardcoded field names. Use IDE search-replace for: errors, tokens, value, token, type, error, updatedField"/>
<property name="ignoreComments" value="true"/>
</module>

<!-- Detect hardcoded RSA algorithm -->
<module name="RegexpSinglelineJava">
<property name="format" value='getInstance\("RSA"\)'/>
<property name="message" value="Use Constants.CryptoAlgorithm.RSA instead of hardcoded 'RSA'"/>
<property name="ignoreComments" value="true"/>
</module>

</module>
</module>
</module>
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.skyflow</groupId>
<artifactId>skyflow-java</artifactId>
<version>2.0.1</version>
<version>2.0.3-dev.5fe0fa5</version>
<packaging>jar</packaging>

<name>${project.groupId}:${project.artifactId}</name>
Expand Down Expand Up @@ -200,7 +200,7 @@
<failsOnError>false</failsOnError>
<consoleOutput>true</consoleOutput>

<excludes>**/generated/**</excludes>
<excludes>**/generated/**,**/logs/**</excludes>
</configuration>
<executions>
<execution>
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/skyflow/VaultClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -808,9 +808,9 @@ private TokenTypeMapping buildTokenType(TokenFormat tokenFormat,

private FileDataDeidentifyAudioDataFormat mapAudioDataFormat(String dataFormat) throws SkyflowException {
switch (dataFormat) {
case "mp3":
case Constants.FileFormatType.MP3:
return FileDataDeidentifyAudioDataFormat.MP_3;
case "wav":
case Constants.FileFormatType.WAV:
return FileDataDeidentifyAudioDataFormat.WAV;
default:
throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidAudioFileType.getMessage());
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/skyflow/config/Credentials.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,13 @@ public class Credentials {
private String credentialsString;
private String token;
private String apiKey;
private String tokenUri;

public Credentials() {
this.path = null;
this.context = null;
this.credentialsString = null;
this.tokenUri = null;
}

public String getPath() {
Expand Down Expand Up @@ -63,4 +65,12 @@ public String getApiKey() {
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}

public String getTokenUri() {
return tokenUri;
}

public void setTokenUri(String tokenUri) {
this.tokenUri = tokenUri;
}
}
3 changes: 2 additions & 1 deletion src/main/java/com/skyflow/errors/ErrorMessage.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.skyflow.utils.Constants;

@SuppressWarnings("checkstyle:MultipleStringLiterals")
public enum ErrorMessage {
// Client initialization
VaultIdAlreadyInConfigList("%s0 Validation error. VaultId is present in an existing config. Specify a new vaultId in config."),
Expand Down Expand Up @@ -44,7 +45,7 @@ public enum ErrorMessage {
MissingClientId("%s0 Initialization failed. Unable to read client ID in credentials. Verify your client ID."),
MissingKeyId("%s0 Initialization failed. Unable to read key ID in credentials. Verify your key ID."),
MissingTokenUri("%s0 Initialization failed. Unable to read token URI in credentials. Verify your token URI."),
InvalidTokenUri("%s0 Initialization failed. Token URI in not a valid URL in credentials. Verify your token URI."),
InvalidTokenUri("%s0 Initialization failed. Invalid Skyflow credentials. The token URI must be a string and a valid URL."),
JwtInvalidFormat("%s0 Initialization failed. Invalid private key format. Verify your credentials."),
InvalidAlgorithm("%s0 Initialization failed. Invalid algorithm to parse private key. Specify valid algorithm."),
InvalidKeySpec("%s0 Initialization failed. Unable to parse RSA private key. Verify your credentials."),
Expand Down
10 changes: 5 additions & 5 deletions src/main/java/com/skyflow/errors/SkyflowException.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public SkyflowException(int httpCode, Throwable cause, Map<String, List<String>>

private void setResponseBody(String responseBody, Map<String, List<String>> responseHeaders) {
this.responseBody = JsonParser.parseString(responseBody).getAsJsonObject();
if (this.responseBody.get("error") != null) {
if (this.responseBody.get(Constants.JsonFieldNames.ERROR) != null) {
setGrpcCode();
setHttpStatus();
setMessage();
Expand All @@ -75,17 +75,17 @@ private void setRequestId(Map<String, List<String>> responseHeaders) {
}

private void setMessage() {
JsonElement messageElement = ((JsonObject) responseBody.get("error")).get("message");
JsonElement messageElement = ((JsonObject) responseBody.get(Constants.JsonFieldNames.ERROR)).get(Constants.JsonFieldNames.MESSAGE);
this.message = messageElement == null ? null : messageElement.getAsString();
}

private void setGrpcCode() {
JsonElement grpcElement = ((JsonObject) responseBody.get("error")).get("grpc_code");
JsonElement grpcElement = ((JsonObject) responseBody.get(Constants.JsonFieldNames.ERROR)).get(Constants.JsonFieldNames.GRPC_CODE);
this.grpcCode = grpcElement == null ? null : grpcElement.getAsInt();
}

private void setHttpStatus() {
JsonElement statusElement = ((JsonObject) responseBody.get("error")).get("http_status");
JsonElement statusElement = ((JsonObject) responseBody.get(Constants.JsonFieldNames.ERROR)).get(Constants.JsonFieldNames.HTTP_STATUS);
this.httpStatus = statusElement == null ? null : statusElement.getAsString();
}

Expand All @@ -98,7 +98,7 @@ public JsonArray getDetails() {
}

private void setDetails(Map<String, List<String>> responseHeaders) {
JsonElement detailsElement = ((JsonObject) responseBody.get("error")).get("details");
JsonElement detailsElement = ((JsonObject) responseBody.get(Constants.JsonFieldNames.ERROR)).get(Constants.JsonFieldNames.DETAILS);
List<String> errorFromClientHeader = responseHeaders.get(Constants.ERROR_FROM_CLIENT_HEADER_KEY);
if (detailsElement != null) {
this.details = detailsElement.getAsJsonArray();
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/skyflow/logs/InfoLogs.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public enum InfoLogs {

// Bearer token generation
EMPTY_BEARER_TOKEN("Bearer token is empty."),
BEARER_TOKEN_EXPIRED("Bearer token is expired."),
BEARER_TOKEN_EXPIRED("Bearer token is invalid or expired."),
GET_BEARER_TOKEN_TRIGGERED("getBearerToken method triggered."),
GET_BEARER_TOKEN_SUCCESS("Bearer token generated."),
GET_SIGNED_DATA_TOKENS_TRIGGERED("getSignedDataTokens method triggered."),
Expand Down
68 changes: 43 additions & 25 deletions src/main/java/com/skyflow/serviceaccount/util/BearerToken.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,21 +34,23 @@ public class BearerToken {
private final String ctx;
private final ArrayList<String> roles;
private final String credentialsType;
private final String tokenUri;

private BearerToken(BearerTokenBuilder builder) {
this.credentialsFile = builder.credentialsFile;
this.credentialsString = builder.credentialsString;
this.ctx = builder.ctx;
this.roles = builder.roles;
this.credentialsType = builder.credentialsType;
this.tokenUri = builder.tokenUri;
}

public static BearerTokenBuilder builder() {
return new BearerTokenBuilder();
}

private static V1GetAuthTokenResponse generateBearerTokenFromCredentials(
File credentialsFile, String context, ArrayList<String> roles
File credentialsFile, String context, ArrayList<String> roles, String overrideTokenUri
) throws SkyflowException {
LogUtil.printInfoLog(InfoLogs.GENERATE_BEARER_TOKEN_FROM_CREDENTIALS_TRIGGERED.getLog());
try {
Expand All @@ -58,7 +60,7 @@ private static V1GetAuthTokenResponse generateBearerTokenFromCredentials(
}
FileReader reader = new FileReader(String.valueOf(credentialsFile));
JsonObject serviceAccountCredentials = JsonParser.parseReader(reader).getAsJsonObject();
return getBearerTokenFromCredentials(serviceAccountCredentials, context, roles);
return getBearerTokenFromCredentials(serviceAccountCredentials, context, roles, overrideTokenUri);
} catch (JsonSyntaxException e) {
LogUtil.printErrorLog(ErrorLogs.INVALID_CREDENTIALS_FILE_FORMAT.getLog());
throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), Utils.parameterizedString(
Expand All @@ -71,7 +73,7 @@ private static V1GetAuthTokenResponse generateBearerTokenFromCredentials(
}

private static V1GetAuthTokenResponse generateBearerTokenFromCredentialString(
String credentials, String context, ArrayList<String> roles
String credentials, String context, ArrayList<String> roles, String overrideTokenUri
) throws SkyflowException {
LogUtil.printInfoLog(InfoLogs.GENERATE_BEARER_TOKEN_FROM_CREDENTIALS_STRING_TRIGGERED.getLog());
try {
Expand All @@ -80,7 +82,7 @@ private static V1GetAuthTokenResponse generateBearerTokenFromCredentialString(
throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidCredentials.getMessage());
}
JsonObject serviceAccountCredentials = JsonParser.parseString(credentials).getAsJsonObject();
return getBearerTokenFromCredentials(serviceAccountCredentials, context, roles);
return getBearerTokenFromCredentials(serviceAccountCredentials, context, roles, overrideTokenUri);
} catch (JsonSyntaxException e) {
LogUtil.printErrorLog(ErrorLogs.INVALID_CREDENTIALS_STRING_FORMAT.getLog());
throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(),
Expand All @@ -89,41 +91,43 @@ private static V1GetAuthTokenResponse generateBearerTokenFromCredentialString(
}

private static V1GetAuthTokenResponse getBearerTokenFromCredentials(
JsonObject credentials, String context, ArrayList<String> roles
JsonObject credentials, String context, ArrayList<String> roles, String overrideTokenUri
) throws SkyflowException {
try {
JsonElement privateKey = credentials.get("privateKey");
JsonElement privateKey = credentials.get(Constants.CredentialFields.PRIVATE_KEY);
if (privateKey == null) {
LogUtil.printErrorLog(ErrorLogs.PRIVATE_KEY_IS_REQUIRED.getLog());
throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.MissingPrivateKey.getMessage());
}

JsonElement clientID = credentials.get("clientID");
JsonElement clientID = credentials.get(Constants.CredentialFields.CLIENT_ID);
if (clientID == null) {
LogUtil.printErrorLog(ErrorLogs.CLIENT_ID_IS_REQUIRED.getLog());
throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.MissingClientId.getMessage());
}

JsonElement keyID = credentials.get("keyID");
JsonElement keyID = credentials.get(Constants.CredentialFields.KEY_ID);
if (keyID == null) {
LogUtil.printErrorLog(ErrorLogs.KEY_ID_IS_REQUIRED.getLog());
throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.MissingKeyId.getMessage());
}

JsonElement tokenURI = credentials.get("tokenURI");
if (tokenURI == null) {
JsonElement tokenURI = credentials.get(Constants.CredentialFields.TOKEN_URI);
if (tokenURI == null && overrideTokenUri == null) {
LogUtil.printErrorLog(ErrorLogs.TOKEN_URI_IS_REQUIRED.getLog());
throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.MissingTokenUri.getMessage());
}

String finalTokenUri = (overrideTokenUri != null) ? overrideTokenUri : tokenURI.getAsString();

PrivateKey pvtKey = Utils.getPrivateKeyFromPem(privateKey.getAsString());
String signedUserJWT = getSignedToken(
clientID.getAsString(), keyID.getAsString(), tokenURI.getAsString(), pvtKey, context
clientID.getAsString(), keyID.getAsString(), finalTokenUri, pvtKey, context
);

String basePath = Utils.getBaseURL(tokenURI.getAsString());
String basePath = Utils.getBaseURL(finalTokenUri);
API_CLIENT_BUILDER.url(basePath);
ApiClient apiClient = API_CLIENT_BUILDER.token("token").build();
ApiClient apiClient = API_CLIENT_BUILDER.token(Constants.ApiToken.TOKEN).build();
AuthenticationClient authenticationApi = apiClient.authentication();

V1GetAuthTokenRequest._FinalStage authTokenBuilder = V1GetAuthTokenRequest.builder().grantType(Constants.GRANT_TYPE).assertion(signedUserJWT);
Expand All @@ -149,11 +153,11 @@ private static String getSignedToken(
final Date createdDate = new Date();
final Date expirationDate = new Date(createdDate.getTime() + (3600 * 1000));
return Jwts.builder()
.claim("iss", clientID)
.claim("key", keyID)
.claim("aud", tokenURI)
.claim("sub", clientID)
.claim("ctx", context)
.claim(Constants.JwtClaims.ISS, clientID)
.claim(Constants.JwtClaims.KEY, keyID)
.claim(Constants.JwtClaims.AUD, tokenURI)
.claim(Constants.JwtClaims.SUB, clientID)
.claim(Constants.JwtClaims.CTX, context)
.expiration(expirationDate)
.signWith(pvtKey, Jwts.SIG.RS256)
.compact();
Expand All @@ -163,7 +167,7 @@ private static String getScopeUsingRoles(ArrayList<String> roles) {
StringBuilder scope = new StringBuilder();
if (roles != null) {
for (String role : roles) {
scope.append(" role:").append(role);
scope.append(Constants.ApiToken.ROLE_PREFIX).append(role);
}
}
return scope.toString();
Expand All @@ -173,11 +177,11 @@ public synchronized String getBearerToken() throws SkyflowException {
LogUtil.printInfoLog(InfoLogs.GET_BEARER_TOKEN_TRIGGERED.getLog());
V1GetAuthTokenResponse response;
String accessToken = null;
if (this.credentialsFile != null && Objects.equals(this.credentialsType, "FILE")) {
response = generateBearerTokenFromCredentials(this.credentialsFile, this.ctx, this.roles);
if (this.credentialsFile != null && Objects.equals(this.credentialsType, Constants.CredentialTypeValues.FILE)) {
response = generateBearerTokenFromCredentials(this.credentialsFile, this.ctx, this.roles, this.tokenUri);
accessToken = response.getAccessToken().get();
} else if (this.credentialsString != null && Objects.equals(this.credentialsType, "STRING")) {
response = generateBearerTokenFromCredentialString(this.credentialsString, this.ctx, this.roles);
} else if (this.credentialsString != null && Objects.equals(this.credentialsType, Constants.CredentialTypeValues.STRING)) {
response = generateBearerTokenFromCredentialString(this.credentialsString, this.ctx, this.roles, this.tokenUri);
accessToken = response.getAccessToken().get();
}
LogUtil.printInfoLog(InfoLogs.GET_BEARER_TOKEN_SUCCESS.getLog());
Expand All @@ -191,6 +195,7 @@ public static class BearerTokenBuilder {
private String ctx;
private ArrayList<String> roles;
private String credentialsType;
private String tokenUri;

private BearerTokenBuilder() {
}
Expand All @@ -200,13 +205,13 @@ private void setCredentialsType(String credentialsType) {
}

public BearerTokenBuilder setCredentials(File credentialsFile) {
setCredentialsType("FILE");
setCredentialsType(Constants.CredentialTypeValues.FILE);
this.credentialsFile = credentialsFile;
return this;
}

public BearerTokenBuilder setCredentials(String credentialsString) {
setCredentialsType("STRING");
setCredentialsType(Constants.CredentialTypeValues.STRING);
this.credentialsString = credentialsString;
return this;
}
Expand All @@ -221,6 +226,19 @@ public BearerTokenBuilder setRoles(ArrayList<String> roles) {
return this;
}

public BearerTokenBuilder setTokenUri(String tokenUri) throws SkyflowException {
if (tokenUri != null && !tokenUri.isEmpty()) {
try {
new java.net.URL(tokenUri);
this.tokenUri = tokenUri;
} catch (MalformedURLException e) {
LogUtil.printErrorLog(ErrorLogs.INVALID_TOKEN_URI.getLog());
throw new SkyflowException(ErrorCode.INVALID_INPUT.getCode(), ErrorMessage.InvalidTokenUri.getMessage());
}
}
return this;
}

public BearerToken build() {
return new BearerToken(this);
}
Expand Down
Loading