The default authentication for SOA Software Open is a custom authentication mechanism, Shared Secret authentication.
It's important to set up authentication for the messages your app sends to an API you’re using. Authentication protects the sender, the receiver, and the message itself. It’s important that the security is strong enough that a third party couldn’t pose as the sender, pose as the receiver, and/or view or change the message content.
Authentication and security are particularly important when money and sensitive personally identifiable information are involved.
Once your app is registered, it's important to set up authentication so that the app can use the API to process messages securely.
In SOA Software Open, as part of setting up your app, you’ll need to choose the security mechanism you’ll use for authentication of your messages. There are two choices:
Note: This topic provides information about setting up authentication for any API hosted in SOA Software Open. For implementation information and examples for a specific API you're using, refer to the documentation for that API.
Both approaches are very secure. Both use a secret key combined with hashing and encoding, and both are sent via HTTPS.
The Shared Secret approach, which is the default, is easier to implement since you don't have to generate public and private keys.
The PKI approach is a little more secure, although both approaches are very secure. The PKI approach is more complex to implement.
When you register your app, the AppID and Shared Secret are automatically generated. The Shared Secret is a binary hashed value, generated within the secure environment of SOA Software Open and known only to you and to SOA Software Open. In the Security Credentials section of the App Details screen you'll see that the Shared Secret option is the default security mechanism.
The Shared Secret approach follows the WS-Security digest authentication mechanism.
The Shared Secret, generated by SOA Software Open, is a 40-character alphanumeric value that acts as the key. An example is shown below.
1008877afabf32efb31f9c974dbeaa688bed0769
You combine the Shared Secret with two other values, hash the result using the SHA-1 secure hashing algorithm, and then encode the hashed value using the Base64 encoding scheme. You can also URL-encode the result, but this isn't required.
The result is sent in the HTTP Authorization message header as the value for the atmosphere_secret_digest parameter.
The API verifies each incoming request using the Shared Secret.
If you choose the Shared Secret security mechanism, your HTTP Authorization header must include the values shown below.
Name | Data Type | Description |
---|---|---|
atmosphere_app_id | String | The AppID assigned to the app in the platform. |
atmosphere_nonce | String | A random string, uniquely generated for each request. For more information, see Generating a Nonce Value. |
atmosphere_secret_digest | String | A value produced by concatenating the nonce, the timestamp, and the Shared Secret, hashing the combined value using SHA-1, and then Base-64 encoding the result. You can also URL-encode the result but this isn't required. |
atmosphere_signature_method | String | A value indicating the signature method. For the Shared Secret approach, the valid value is Digest. |
atmosphere_timestamp | String | The timestamp of the request, expressed as the number of milliseconds since January 1, 1970 00:00:00 GMT. The timestamp must be a positive integer and must be greater than or equal to the timestamp used in previous requests. |
atmosphere_version | String | The SOA Software Open version. Optional. If present, the valid value must be 1.0. |
More information about the shared secret approach is given in these sections:
The process flow diagram below shows an overview of API request authentication with the shared secret security mechanism.
Below is an example of an Authorization header with app authentication parameters, when you use the shared secret approach. The sequence of the parameters isn't significant, but all parameters must be present with valid values.
Note: The value for the realm is determined by the www-Authenticate header. Make sure the value you set in the Authorization: SOA Software Open header matches the value received for the attribute from the server.
Authorization: Atmosphere realm="http://atmosphere", atmosphere_app_id="development-AS0iTmhoGaE6Y9sWhUkvcL6T", atmosphere_nonce="1326409129918", atmosphere_secret_digest="wOJIO9A2W5mFwDgiDvZbTSMK%2FPY%3D", atmosphere_digest_method="SHA1", atmosphere_timestamp="1326755565940", atmosphere_version="1.0"
A nonce is a random string that is uniquely generated for each request. The nonce allows the API providers to verify that a request has never been made before. A nonce is sent in the message header for both Shared Secret and PKI security mechanisms. In the Shared Secret mechanism, the same nonce value sent in the message header is also used in creating the Secret Digest.
The way you create the nonce will depend on your development environment. Most programming languages include a method for creating a nonce. Below is an example of generating a nonce value in Java:
Import java.security.SecureRandom: Random rand = SecureRandom.getInstance ("SHA1PRNG"); long nonce = rand.nextLong();
The timestamp of the request is sent in the message header, for both Shared Secret and PKI security mechanisms. In the Shared Secret mechanism it is also used in creating the Secret Digest.
The timestamp must be in Unix epoch time, expressed as the number of milliseconds since January 1, 1970 00:00:00 GMT. The timestamp must be a positive integer and must be greater than or equal to the timestamp used in previous requests. In most implementations, the timestamp is taken from the host server. It's important that the timestamp in the message is accurate; if the timestamp is off, the message might be rejected.
For more information on Unix epoch time, and examples of implementation of the timestamp in different programming languages, see http://www.epochconverter.com (scroll down).
SHA-1 is a cryptographic hash function, broadly used and trusted.
When you hash a value with SHA-1, the hash function returns a 160-bit string. This is the message digest. The value is hashed and sent with the message; at the receipt point, the value is hashed again, and the two hash values are compared. When the two hash values match, it is a secure, reliable indication that the message hasn't changed; the message at the receipt point is an accurate duplication of the message at the send point.
If you're using the Shared Secret security mechanism, you concatenate the nonce, the timestamp, and the Shared Secret, and then you hash that combined value using SHA-1. You then encode the result, and send it in the message header as the value for the atmosphere_secret_digest parameter.
The formula for computing the hash is:
atmosphere_secret_digest = Base64 ( SHA-1 ( nonce + created + AppSecret ) )
Below is an example of a hashed base string:
1326409129918+1326755565940+2d9d42b42a4e2abc1fa5489d5081e03b95818ffd
When you concatenate the nonce, timestamp, and app secret into a base string to be hashed, you'll need to make sure the concatenated value is a byte value before hashing. The hashing algorithm requires the input parameter to be in bytes. Depending on your app, you might need to use encoding to get a byte value. If so, use UTF-8 encoding.
Below is an example using Java.
MessageDigest md = MessageDigest.getInstance("SHA1"); md.update(baseString.getBytes("UTF-8")); or md.update(baseString.getBytes()); String digest = encodeAsBase64String(md.digest());
Note: The example above is part of a larger Java sample for a specific API. For more information, refer to the implementation examples for the API you're using.
The Base64 encoding scheme converts binary data into an ASCII string.
If you're using the Shared Secret security mechanism, you must encode the binary hash value that you created using the SHA-1 secure hash algorithm. Encoding turns it into ASCII string format. It's common practice to encode data to make sure it remains intact without modification during transport by HTTP or HTTPS.
Once the hash is encoded, the next step is to send the encoded value in the message header as the value for the atmosphere_secret_digest parameter.
If there's a problem with your HTTPS header, you might see one of the error messages shown below.
Code | Description |
---|---|
1010701 | Required HTTP header parameter missing. [{0}] |
1010702 | One or more invalid HTTP header parameters. |
1010703 | Invalid Nonce. The value of the atmosphere_nonce field has already been used. |
1010704 | Invalid timestamp. The value of the atmosphere_timestamp field is out of range. |
1010705 | Signature or digest algorithm is not supported. [{0}] |
1010706 | Signature or digest verification failed. |
1010707 | Missing nonce. The atmosphere_nonce field value is required. |
1010708 | Unable to verify signature. There is no public key associated with the app. |
1010709 | Authentication scheme is invalid or missing. |
1010710 | Invalid AppID. The value [{0}] in the atmosphere_app_id field is invalid or missing. |
1010711 | Unable to verify signature. There is no shared secret associated with the app. |
1010712 | Invalid timestamp. Timestamp must be Unix epoch time in milliseconds. |
If for any reason you know or suspect that your app's Shared Secret might have been compromised, you must generate a new Shared Secret to replace the old one. You can generate a new Shared Secret in the Community Platform
Note: It might take up to five minutes for the new key to take effect. During that time, messages sent using the new key will fail. It's best to wait for five minutes before sending messages with the new key.
Below is an example of how to create the atmosphere_secret_digest value in Java.
//Use the shared secret of app on file String sharedSecret = "1008877afabf32efb31f9c974dbeaa688bed0769"; //Generate the nonce value Import java.security.SecureRandom: Random rand = SecureRandom.getInstance ("SHA1PRNG"); long nonce = rand.nextLong(); //Get the timestamp in milliseconds long timestamp = System.currentTimeMillis(); // Concatenate the nonce, timestamp, and Shared Secret String baseString = String.valueOf(nonce) + String.valueOf(timestamp) + sharedSecret; // Hash the concatenated value into a message digest using SHA-1 MessageDigest md = MessageDigest.getInstance("SHA1"); md.update(baseString.getBytes()); // Encode the message digest using Base-64 encoding String digest = encodeAsBase64String(md.digest());
When you register your app in SOA Software Open, in the Security Credentials section of your App Details you'll see that the Shared Secret option is the default.
If you want to use Public Key Infrastructure (PKI) for secure message signing, click the button to choose Public Key Integration. You'll need to get a public/private key pair and upload the public key to SOA Software Open, as explained later in this document. In the custom app code you will sign the API requests using the private key. The API verifies each incoming request using the public key.
More information about authenticating with PKI is given in these sections:
The process flow diagram below shows an overview of API request authentication with PKI.
You can use the OpenSSL open source product to produce a public/private key pair. For more information on OpenSSL, refer to www.openssl.org.
If you are developing the application using the Microsoft Windows OS you can get an adaptation of OpenSSL for the Windows platform from the following location: http://code.google.com/p/openssl-for-windows/downloads/list.
C:\openssl>bin\openssl req -config openssl.cnf -out csr.csr -new -newkey rsa:2048 -keyout privatekey.key
Note: Anything with an empty bracket set [] is not required.
Below is an example of what you might see in the command-line window.
This process creates your public/private key pair in the c:\openssl folder. The key pair includes the files shown below.
File name | Key type | Comments |
---|---|---|
privatekey.key | private key | Make sure you save a copy of the private key in a safe place. If you lose this key you will need to generate a new key pair. You will sign your request using the private key. For more information, see Composing the Signature. |
csr.csr | public key | Upload this file to the SOA Software Open portal. The API uses this file to verify the signature of your requests. |
Important: Upload the file csr.csr to the SOA Software Open portal.
If you are a Java developer and have worked with cryptography in Java, you might be familiar with the concept of a keystore. A keystore is a file used to store and deploy certificates and private keys in a single package. You can create a keystore using OpenSSL as explained above. However, as a Java developer, it is probably far more convenient to use keytool, a key and certificate management utility that's distributed as part of the Java Development Kit (JDK).
You can use keytool to create both the keystore and the CSR associated with the private key in the keystore. Once you've created your CSR, you upload it to SOA Software Open just like any other CSR. Your Java code reads your private key, used for signing the base string used in API request headers, from the keystore file you create.
Since the keytool utility is part of the JDK, you don't have to download anything to create your Java keystore. Just follow the steps below.
Note: The procedure below assumes that your JDK bin directory is in your Windows system path.
keytool -genkey -alias <keystorealias> -keyalg RSA -keystore <keystore_filename>.p12 -storetype PKCS12 -keypass <password> -keysize 2048
keytool -certreq -alias <keystorealias> -keystore <keystore_filename>.p12 -file <csr_filename>.csr -storetype PKCS12
The illustration below shows the steps to create a keystore called keystore.p12 with an alias of mykeystore and the password changeme.
The illustration below shows how to create a CSR called csr.csr from keystore.p12.
Note: For implementation examples, check the authentication documentation for the specific API you're using.
IMPORTANT : Upload the file CSR.csr to the SOA Software Open portal.
The signature process follows a similar approach to the OAuth 1.0 standard. The platform uses an HTTP Extension header to support its app authentication scheme. This Extension header is named Atmosphere (not case-sensitive). It uses the standard HTTP Authorization header and WWW-Authenticate response header to pass app-related authentication parameters. The HTTP query string can also be used to pass authentication data for cases where the app cannot directly manipulate HTTP headers.
API providers can indicate their support for the extension by returning the SOA Software Open HTTP WWW-Authenticate header in response to app requests for protected resources. Below is an example:
WWW-Authenticate: Atmosphere realm="http://atmosphere
Apps should send their credentials in the HTTP Authorization header. If you choose the Public Key Integration approach for your app security, your HTTP Authorization header must include the values shown below.
Important: The sequence of the header attributes is critical and must exactly match the order below.
Name | Data Type | Description |
---|---|---|
atmosphere_app_id | String | The AppID assigned to the app in the platform. |
atmosphere_nonce | String | A random string, uniquely generated for each request. The nonce allows the API providers to verify that a request has never been made before and helps prevent replay attacks when requests are made over a non-secure channel. |
atmosphere_signature_method | String | Indicates the signature method used. Valid values are SHA1withRSA or NONE. The NONE signature method is used for APIs that don't require security. In this case, only the atmosphere_app_id is required in the SOA Software Open HTTP Authorization headers. |
atmosphere_signature | String | The signature value. See next section for how the signature value is calculated. |
atmosphere_timestamp | String | The timestamp of the request, expressed as the number of milliseconds since January 1, 1970 00:00:00 GMT. The timestamp must be a positive integer and must be greater than or equal to the timestamp used in previous requests. |
atmosphere_version | String | The SOA Software Open version. Optional. If present, the valid value must be 1.0. |
Below is an example of an Authorization header with app authentication parameters. Make sure you list the parameters in the sequence shown below.
Note: The value for the realm is determined by the www-Authenticate header. Make sure the value you set in the Authorization: SOA Software Open header matches the value received for the attribute from the server.
Authorization: SOA Software Open realm="http://atmosphere", atmosphere_app_id="development-7FSXeNRkVRJ8XtAurgaea65R ", atmosphere_nonce="1323732744354", atmosphere_signature_method="SHA1withRSA", atmosphere_signature="wOJIO9A2W5mFwDgiDvZbTSMK%2FPY%3D", atmosphere_timestamp="1323732744354", atmosphere_version="1.0"
Below is an example of an Authorization header for an API that doesn't require authentication:
Authorization: SOA Software Open realm="http://atmosphere", atmosphere_app_id="http://www.open.com/app/101", atmosphere_signature_method="NONE"
Note: In case the client, such as an Ajax client in the browser or an Android app, cannot set the HTTP Authorization header, you can set the required SOA Software Open authorization header parameters in the HTTP query string.
There are several steps to composing the signature:
The first step in composing the digital signature is to create the content. Once that's done, the data is signed using the signature algorithm.
Note: The atmosphere_signature parameter must be excluded from the Signature Base String.
Below is an example of the Signature Base String.
POST&https://api.sandbox.yoursandbox.com/APIName/Payment/v1/MethodName &atmosphere_app_id=Atmosphere-7FSXeNRkVRJ8XtAurgaea65R &atmosphere_nonce=1323732744354&atmosphere_signature_method=SHA1withRSA &atmosphere_timestamp=1323732744354&atmosphere_version=1.0
Once the Signature Base String is constructed, the next step is signing:
The example below shows the same message header as it would be if created with each approach.
Some parameters are common to both approaches:
In the example below, the message header uses the Shared Secret approach, with a Shared Secret value of 1008877afabf32efb31f9c974dbeaa688bed0769. The atmosphere_secret_digest value is the hashed value of nonce + timestamp + shared secret.
Atmosphere realm="http://atmosphere", atmosphere_app_id="Atmosphere-2f97rkSViLn6yd7syPtRiG7q", atmosphere_nonce="1328745832972", atmosphere_timestamp="1328745832972", atmosphere_digest_method="SHA1", atmosphere_secret_digest="fr3u4BCMJv03THDqsj5c6RQMUWk=", atmosphere_version="1.0"
In the example below, the message header uses the PKI approach. The atmosphere-signature value is the signed value of the signature base string (see signature base string).
Atmosphere realm="http://atmosphere", atmosphere_app_id="Atmosphere-2f97rkSViLn6yd7syPtRiG7q", atmosphere_nonce="1328745832972", atmosphere_timestamp="1328745832972" atmosphere_signature_method="SHA1withRSA", atmosphere_signature="XKYtUsH7ta8I5mbZaZebm4b6NLjAVSGcK3op9lJxWC%2FlpNLxAm1GoHoMkKzLUh %2BN7QdEBjR6ufgKMD%2BTWK4fPT2uXbHWNuOOTM4qUizrRymPxuAXEWhmECEB4WL7zr9UmWG7OGDsyuDUOt 93nAnVvfqinF0bC%2FnWBAH%2FelZlX%2FUMtO29%2BNrMq7ep0B%2BWKEosJmCFBtfgk72kRYl5rKsDqDm2m gIFyHPWoFvC5WJiqtXTqGEaNxSbdWweaCaLqHNRnXowozOLMYYnnEd%2FTSFF0E5CrJBTzOq5Wvixnt6iJqWE J0ywIc%2FPjVFs5muYOv30Lno44F0w6b3vjKTHWOJHEg%3D%3D", atmosphere_version="1.0"