mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-09-22 21:55:39 +00:00
bug6095: added persistence for AI Core Credentials, using AES encryption with random salt
This commit is contained in:
@@ -7,6 +7,7 @@ import java.net.MalformedURLException;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
import com.sap.sse.aicore.impl.CredentialsParserImpl;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
public interface CredentialsParser {
|
||||
static CredentialsParser create() {
|
||||
@@ -16,4 +17,17 @@ public interface CredentialsParser {
|
||||
Credentials parse(Reader r) throws IOException, ParseException;
|
||||
|
||||
Credentials parse(CharSequence s) throws ParseException, MalformedURLException;
|
||||
|
||||
/**
|
||||
* @return a pair of which the {@link Pair#getA() first} component represents the encoded credentials, using a
|
||||
* random "salt" returned as the {@link Pair#getB() second} component of the pair returned. These can be
|
||||
* used as the two arguments to {@link #parseFromEncoded(CharSequence)} to obtain {@link Credentials}
|
||||
* equivalent to the {@code credentials} passed to this method again.
|
||||
*/
|
||||
Pair<String, String> getAsEncodedString(Credentials credentials);
|
||||
|
||||
/**
|
||||
* The inverse for {@link #getAsEncodedString(Credentials)}
|
||||
*/
|
||||
Credentials parseFromEncoded(CharSequence encoded, String salt);
|
||||
}
|
||||
|
||||
@@ -94,6 +94,18 @@ public class CredentialsImpl implements Credentials {
|
||||
return token;
|
||||
}
|
||||
|
||||
String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
String getClientSecret() {
|
||||
return clientSecret;
|
||||
}
|
||||
|
||||
URL getXsuaaUrl() {
|
||||
return xsuaaUrl;
|
||||
}
|
||||
|
||||
String fetchToken() throws URISyntaxException, UnsupportedOperationException, ClientProtocolException, IOException, ParseException {
|
||||
final HttpPost postRequest = new HttpPost(new URI(xsuaaUrl.toString() + CLIENT_CREDENTIALS_PATH));
|
||||
postRequest.setHeader("Content-Type", "application/x-www-form-urlencoded");
|
||||
|
||||
@@ -3,6 +3,11 @@ package com.sap.sse.aicore.impl;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.net.MalformedURLException;
|
||||
import java.util.Base64;
|
||||
import java.util.Random;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
@@ -10,6 +15,7 @@ import org.json.simple.parser.ParseException;
|
||||
|
||||
import com.sap.sse.aicore.Credentials;
|
||||
import com.sap.sse.aicore.CredentialsParser;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
|
||||
public class CredentialsParserImpl implements CredentialsParser {
|
||||
private final static String CLIENT_ID = "clientid";
|
||||
@@ -44,4 +50,60 @@ public class CredentialsParserImpl implements CredentialsParser {
|
||||
final String aiApiUrl = (String) serviceURLs.get(AI_API_URL);
|
||||
return new CredentialsImpl(clientId, clientSecret, url, identityZone, identityZoneId, appName, aiApiUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pair<String, String> getAsEncodedString(Credentials credentials) {
|
||||
final String clientId = ((CredentialsImpl) credentials).getClientId();
|
||||
final String clientSecret = ((CredentialsImpl) credentials).getClientSecret();
|
||||
final String url = ((CredentialsImpl) credentials).getXsuaaUrl().toString();
|
||||
final String identityZone = credentials.getIdentityZone();
|
||||
final String identityZoneId = credentials.getIdentityZoneId();
|
||||
final String appName = credentials.getAppName();
|
||||
final String aiApiUrl = credentials.getAiApiUrl().toString();
|
||||
final JSONObject jsonCredentials = new JSONObject();
|
||||
jsonCredentials.put(CLIENT_ID, clientId);
|
||||
jsonCredentials.put(CLIENT_SECRET, clientSecret);
|
||||
jsonCredentials.put(URL, url);
|
||||
jsonCredentials.put(IDENTITY_ZONE, identityZone);
|
||||
jsonCredentials.put(IDENTITY_ZONE_ID, identityZoneId);
|
||||
jsonCredentials.put(APP_NAME, appName);
|
||||
final JSONObject serviceURLs = new JSONObject();
|
||||
jsonCredentials.put(SERVICE_URLS, serviceURLs);
|
||||
serviceURLs.put(AI_API_URL, aiApiUrl);
|
||||
final String salt = createRandomSalt();
|
||||
SecretKeySpec secretKey = new SecretKeySpec(salt.getBytes(), "AES"); // 16-byte key for AES
|
||||
try {
|
||||
Cipher cipher = Cipher.getInstance("AES");
|
||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
||||
byte[] encryptedBytes = cipher.doFinal(jsonCredentials.toJSONString().getBytes());
|
||||
return new Pair<>(Base64.getEncoder().encodeToString(encryptedBytes), salt);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private String createRandomSalt() {
|
||||
final Random random = new Random();
|
||||
final int numberOfCharacters = 16;
|
||||
final char[] chars = new char[numberOfCharacters];
|
||||
for (int i=0; i<numberOfCharacters; i++) {
|
||||
chars[i] = (char) (((int) 'A') + random.nextInt((int) 'z' - (int) 'A'));
|
||||
}
|
||||
return new String(chars);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Credentials parseFromEncoded(CharSequence encoded, String salt) {
|
||||
final byte[] decodedBytes = Base64.getDecoder().decode(encoded.toString().getBytes());
|
||||
final SecretKeySpec secretKey = new SecretKeySpec(salt.getBytes(), "AES"); // 16-byte key for AES
|
||||
try {
|
||||
final Cipher cipher = Cipher.getInstance("AES");
|
||||
cipher.init(Cipher.DECRYPT_MODE, secretKey);
|
||||
final byte[] decryptedBytes = cipher.doFinal(decodedBytes);
|
||||
final String decryptedString = new String(decryptedBytes);
|
||||
return parse(decryptedString);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user