Can we use the same signer object to sign all the requests? - oracle-cloud-infrastructure

I need to make mutiple rest api calls for fetching instance, volume and vnic details. Can i reuse the same signer object created for signing the other calls?
Signer object method
public RequestSigner getSigner(Properties properties, String pemFilePath, String apiKey) {
InputStream privateKeyStream;
PrivateKey privateKey = null;
try {
privateKeyStream = Files.newInputStream(Paths.get(pemFilePath));
privateKey = PEM.readPrivateKey(privateKeyStream);
} catch (InvalidKeySpecException e) {
// throw new RuntimeException("Invalid format for private key");
properties.setProperty(OracleCloudConstants.CUSTOM_DC_ERROR,
FormatUtil.getString("am.webclient.oraclecloud.customdc.invalidformat"));
AMLog.debug("OracleCloudDataCollector::CheckAuthentication()::Invalid format for private key::"
+ e.getMessage());
e.printStackTrace();
} catch (IOException e) {
properties.setProperty(OracleCloudConstants.CUSTOM_DC_ERROR,
FormatUtil.getString("am.webclient.oraclecloud.customdc.failedload"));
AMLog.debug(
"OracleCloudDataCollector::CheckAuthentication()::Failed to load private key::" + e.getMessage()); //No I18N
e.printStackTrace();
// throw new RuntimeException("Failed to load private key");
}
RequestSigner signer = null;
if (privateKey != null) {
signer = new RequestSigner(apiKey, privateKey);
}
return signer;
}

One signer object may be used to sign multiple requests. In fact, the SDK implementation does this too.
It is not clear what version of the SDK you are using. In version 1.5.7 (the most recent at the time of writing), com.oracle.bmc.http.signing.RequestSigner (https://github.com/oracle/oci-java-sdk/blob/master/bmc-common/src/main/java/com/oracle/bmc/http/signing/RequestSigner.java#L16) is an interface which cannot be new’ed as per the snippet above.

Related

How to read .pem file with a passphrase in Oracle Cloud Infrastructure?

I need to monitor Oracle Cloud Compute VM using REST API. I found the following lines of code for Signing with headers in Oracle documentation.
String privateKeyFilename = "/.oci/oci_api_key.pem";
PrivateKey privateKey = loadPrivateKey(privateKeyFilename);
RequestSigner signer = new RequestSigner(apiKey, privateKey);
loadPrivateKey(privateKeyFilename) Method
private static PrivateKey loadPrivateKey(String privateKeyFilename) {
System.out.println(SystemUtils.getUserHome().toString() + Paths.get(privateKeyFilename));
try (InputStream privateKeyStream = Files
.newInputStream(Paths.get(SystemUtils.getUserHome().toString() + privateKeyFilename))) {
return PEM.readPrivateKey(privateKeyStream);
} catch (InvalidKeySpecException e) {
throw new RuntimeException("Invalid format for private key");
} catch (IOException e) {
throw new RuntimeException("Failed to load private key");
}
}
Do these lines will cover reading the file with passphrase. Any inputs?

How do I send a HTTP request using OAUTH2 in Android?

I am trying to retrieve the data from my account by connecting to the Fitbit API. I have my app returning the Access Token I need to make the HTTP Request that returns the JSON but anything that I try, it returns an error. I have two Activities - MainActivity.java and TestActivity.java
In MainActivity.java I am simply opening a Chrome Custom Tab to direct the user to the Fitbit Authentication(Login) page. Once the user enters their details they are redirected back to the TestActivity.java as per the Fitbit API documentation. I am then printing the Acess Token which proves to me that it is connecting to the API.
What I need to do it make an HTTP request to returns the sleep data in JSON format. I know how to do it in Java but I am unsure how to do it in Android using the AsyncTask way. Any help is appreciated!
public class TestActivity extends AppCompatActivity {
String string;
String token;
#Override
protected void onNewIntent(Intent intent) {
string = intent.getDataString();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
onNewIntent(getIntent());
//Toast.makeText(TestActivity.this, string , Toast.LENGTH_LONG).show();
Log.e("TAG", string);
Log.e("TAG", string.substring(string.indexOf("&access_token")+14));
token = string.substring(string.indexOf("&access_token")+14);
Context context = getApplicationContext();
Toast toast = Toast.makeText(context,"Access Token: "+ token,Toast.LENGTH_LONG );
Log.i("TAG", "Access Token: "+ token);
new JSONTask().execute("https://api.fitbit.com/1.2/user/-/sleep/date/2018-01-30.json");
}
public class JSONTask extends AsyncTask<String,String,String>
{
#Override
protected String doInBackground(String... params) {
HttpURLConnection connection = null;
BufferedReader reader = null;
try
{
URL url = new URL(params[0]);
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", "Bearer " + token);
connection = (HttpURLConnection) url.openConnection();
connection.connect();
InputStream stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream));
StringBuffer buffer = new StringBuffer();
String line = "";
while((line = reader.readLine()) !=null)
{
buffer.append(line);
}
return buffer.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String s)
{
super.onPostExecute(s);
Log.i("TAG", s);
}
}
I ended up having a breakthrough with this question. I figured out that I was extracting the Access Token incorrectly. So, instead of doing the following:
token = string.substring(string.indexOf("&access_token")+14);
I instead had to use this:
token = string.substring(string.indexOf("&access_token")+36,308);
The App was then able to make the necessary HTTP request to the Fitbit API which returned the JSON data that I needed.
One order of codes should be changed for preventing FC.
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", "Bearer " + token);

OAuth2 multiple keys, public key migration, Resource Server

My System: A Security Provider generates JWT Tokens based on a Private Key. The Private Key belongs to a Certificate which will expire.
Is it possible to set multiple Public Keys in Resource Server?
I would like to do a rolling Update, so for a short time it has to Support the old Public Key and a new Public Key. Thats a default use case because the certificates expires.?
Can oauth/token_key deliver multiple Keys or just one?
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
Resource resource = new ClassPathResource("public.txt");
String publicKey = null;
try {
publicKey = IOUtils.toString(resource.getInputStream());
}
catch (final IOException e) { throw new RuntimeException(e);
}
**converter.setVerifierKey(publicKey);**
**converter.setVerifierKeys(publicKey1, publicKey2);?**
return converter;
}
http://www.baeldung.com/spring-security-oauth-jwt
Thanks
This is not standard practice and Spring's jwt framework does not support multiple security providers (or multiple active verifier keys) out-of-the-box. Having said that, what you wish to do is theoretically possible. You would have wire-up a new implementation for the AccessTokenConverter similar to the JwtAccessTokenConverter, but implement the decode method like this:
protected Map<String, Object> decode(String token) {
try {
Jwt jwt = JwtHelper.decodeAndVerify(token, verifier1);
String content = jwt.getClaims();
Map<String, Object> map = objectMapper.parseMap(content);
if (map.containsKey(EXP) && map.get(EXP) instanceof Integer) {
Integer intValue = (Integer) map.get(EXP);
map.put(EXP, new Long(intValue));
}
return map;
}
catch (Exception e) {
//try the other verifier
try {
Jwt jwt = JwtHelper.decodeAndVerify(token, verifier2);
String content = jwt.getClaims();
Map<String, Object> map = objectMapper.parseMap(content);
if (map.containsKey(EXP) && map.get(EXP) instanceof Integer) {
Integer intValue = (Integer) map.get(EXP);
map.put(EXP, new Long(intValue));
}
return map;
}
catch(InvalidTokenException te){
throw te;
}catch (Exception e) {
throw new InvalidTokenException("Cannot convert access token to JSON", e);
}
}
}
Essentially, the code above trys to verify the first key but if any exception is thrown it will try to validate the second one.
I would also suggest you override to tokenConverter to split the provided token by some delimiter like a "." or something that is not in the encoding char set of your hash algo that generates the verifier key. Then when calling the you could do: setVerifierKey("verifierKey1" + delimiter + "verifierKey2")
Note: I have not tested this code, just some thoughts :)

Spying method calls the actual Method

I am writing a JUnit with Mockito. But on the line
when(encryptDecryptUtil.getKeyFromKeyStore(any(String.class))).thenReturn(keyMock);
It calls the actual method, which is causing the test failure. Interesting point is that it directly makes the actual call at start of the test case when when()...thenReturn() statemnts gets executed. Can you please tell me how I can fix this? My test is as per below
#Test
public void testDecryptData_Success() throws NoSuchPaddingException, NoSuchAlgorithmException, BadPaddingException, IllegalBlockSizeException {
encryptDecryptUtil = spy(new EncryptDecryptUtil());
Key keyMock = Mockito.mock(Key.class);
when(encryptDecryptUtil.getKeyFromKeyStore(any(String.class))).thenReturn(keyMock);
String inputData = "TestMessage";
String version = GetPropValues.getPropValue(PublisherConstants.KEYSTORE_VERSION);
byte[] enCryptedValue= new byte[] {9,2,5,8,9};
Cipher cipherMock = Mockito.mock(Cipher.class);
when(Cipher.getInstance(any(String.class))).thenReturn(cipherMock);
when(cipherMock.doFinal(any(byte[].class))).thenReturn(enCryptedValue);
String encryptedMessage = encryptDecryptUtil.encryptData(inputData);
assert(encryptedMessage.contains(version));
assertTrue(!encryptedMessage.contains(inputData));
}
On the third line it self, it calls the actual method.
Main code is as per below.
public class EncryptDecryptUtil {
private String publicKeyStoreFileName =
GetPropValues.getPropValue(PublisherConstants.KEYSTORE_PATH);
private String pubKeyStorePwd = "changeit";
private static final String SHA1PRNG = "SHA1PRNG";
private static final String pubKeyAlias="jceksaes";
private static final String JCEKS = "JCEKS";
private static final String AES_PADDING = "AES/CBC/PKCS5Padding";
private static final String AES = "AES";
private static final int CONST_16 = 16;
private static final int CONST_0 = 0;
private static final String KEY_STORE = "aes-keystore";
private static final String KEY_STORE_TYPE = "jck";
private static final Logger logger = Logger.getLogger(KafkaPublisher.class);
public Key getKeyFromKeyStore( String keystoreVersion) {
KeyStore keyStore = null;
Key key = null;
try {
keyStore = KeyStore.getInstance(JCEKS);
FileInputStream stream = null;
stream = new FileInputStream(publicKeyStoreFileName+KEY_STORE+PublisherConstants.UNDERSCORE+keystoreVersion+PublisherConstants.DOT+KEY_STORE_TYPE);
keyStore.load(stream, pubKeyStorePwd.toCharArray());
stream.close();
key = keyStore.getKey(pubKeyAlias, pubKeyStorePwd.toCharArray());
} catch (KeyStoreException e) {
e.printStackTrace();
}
catch (FileNotFoundException e) {
logger.error("Error Inside getKeyFromKeyStore, Exception = " + e);
e.printStackTrace();
} catch (CertificateException e) {
logger.error("Error Inside getKeyFromKeyStore, Exception = " + e);
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
logger.error("Error Inside getKeyFromKeyStore, Exception = " + e);
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
logger.error("Error Inside getKeyFromKeyStore, Exception = " + e);
e.printStackTrace();
} catch (IOException e) {
logger.error("Error Inside getKeyFromKeyStore, Exception = " + e);
e.printStackTrace();
}
return key;
}
public String encryptData(String data) {
String keystoreVersion = GetPropValues.getPropValue(PublisherConstants.KEYSTORE_VERSION);
SecretKey secKey = new SecretKeySpec(getKeyFromKeyStore(keystoreVersion).getEncoded(), AES);
String base64EncodedEncryptedMsg = null;
Cipher cipher = null;
try { ------- Logic -------------------}
catch() { }
}
}
Have a look at the "Important gotcha on spying real objects" section of the Spy documentation.
Essentially, you cannot use the when(...).thenReturn(...) pattern with Spies, because as you have discovered, it calls the real method!
Instead, you use a different pattern which does exactly the same thing:
doReturn(...).when(spy).someMethod();
So, for your example:
doReturn(keyMock).when(encryptDecryptUtil).getKeyFromKeyStore(any(String.class));
Some advice which is unrelated to your question: If I read your code correctly, then EncryptDecryptUtil is the class that you are testing. As a general rule, you should not mock, stub, or spy on the object that you are actually testing, because then you are not testing the true object. You are actually testing a version of the object creating by the Mockito library. Furthermore, it's an uncommon pattern which will make your tests hard to read and maintain. If you find yourself having to do this, then the best thing would be to refactor your code so that the methods you are mocking (or spying on) and the methods you are testing are in different classes.

Mockito Stubbing

Listed below is a method I am trying to test using Junit and Mockito
Java Code
public String getAuthenticationService() {
Authentication endpoint;
String token = "";
try {
URL wsdlURL = new URL(authenticationURL);
SoapService service = new SoapService(wsdlURL,
new QName("SomeQName",
"SoapService"));
endpoint = service.getAuthenticationPort();
token = endpoint.authenticate(username, password);
} catch (Exception e) {
throw new GenericException(
"OpenText AuthenticationService not working Error is "
+ e.toString());
}
return token;
}
Junit method
public void testGetAuthenticationService()
throws AuthenticationException_Exception {
AuthenticationService mockService = Mockito
.mock(AuthenticationService.class);
Authentication mockEndpoint = Mockito.mock(Authentication.class);
Mockito.when(mockService.getAuthenticationPort()).thenReturn(
mockEndpoint);
Mockito.when(mockEndpoint.authenticate(username, password)).thenReturn(
token);
}
When I run the Junit test case the endpoint.authenticate tries to connect to the actaul soap service, and the method stubbing is not working, what am I doing wrong here
Your mockService seems to be a good replacement for your SoapService, but you aren't giving yourself an opportunity to refer to it in your code. Your test calls the code, which calls the SoapService constructor, so you get a real service. Consider this refactor:
public String getAuthenticationService() {
try {
URL wsdlURL = new URL(authenticationURL);
SoapService service = new SoapService(wsdlURL,
new QName("SomeQName", "SoapService"));
return getAuthenticationService(service);
} catch (Exception e) {
throw new GenericException(
"OpenText AuthenticationService not working Error is "
+ e.toString());
}
}
/** package-private for testing - call this from your test instead */
String getAuthenticationService(AuthenticationService service) {
try {
Authentication endpoint = service.getAuthenticationPort();
String token = endpoint.authenticate(username, password);
return token;
} catch (Exception e) {
throw new GenericException(
"OpenText AuthenticationService not working Error is "
+ e.toString());
}
}
Now you can pass your mockService into getAuthenticationService(service) and your code will use your mock rather than the SoapService it creates inline.
As as alternative, you can also give yourself a seam by wrapping the SoapService constructor:
/** overridden in tests */
protected AuthenticationService createSoapService(String url, QName qname) {
return new SoapService(url, qname);
}
public String getAuthenticationService() {
try {
URL wsdlURL = new URL(authenticationURL);
SoapService service = createSoapService(wsdlURL,
new QName("SomeQName", "SoapService"));
Authentication endpoint = service.getAuthenticationPort();
String token = endpoint.authenticate(username, password);
return token;
} catch (Exception e) {
throw new GenericException(
"OpenText AuthenticationService not working Error is "
+ e.toString());
}
}
// in your test:
SystemUnderTest yourSystem = new YourSystem() {
#Override protected AuthenticationService createAuthenticationService(
String url, QName qname) {
return mockService;
}
}