How do I verify the Subject of X509 Certificate using rails-auth? - ruby-on-rails-4

I am trying to secure one endpoint that I have for the Docusign Connect API. I have checked the Sign Message with X509 Certificate on docusign connect API configuration.
The Client Certificate Common Name is added to the Docusign Account as well.
I am trying to validate the subject sent using the rails-auth gem.
Following is the content of the ACL file(acl.yml)
---
- resources:
- method: POST
path: /
allow_x509_subject:
cn: "the common name"
I have added the following in the config.ru file
app = Rails.application
acl = Rails::Auth::ACL.from_yaml(
File.read("path of the acl.yml"),
matchers: { allow_x509_subject: Rails::Auth::X509::Matcher }
)
acl_auth = Rails::Auth::ACL::Middleware.new(app, acl: acl)
x509_auth = Rails::Auth::X509::Middleware.new(
acl_auth,
ca_file: "path_to_the_pem_file.crt",
cert_filters: { 'X-SSL-Client-Cert' => :pem })
run x509_auth
I am getting the following exception.
*** Exception Rails::Auth::NotAuthorizedError in Rack application object (unauthorized request)
The Common Name that is added in the Docusign Account is the same as the one that I have mentioned in YML file. Could somebody please help me in finding the issue here?
I am using Ruby 2.2.2 with rails 4.2.2, rails-auth 2.0.3

The best way to secure connect endpoint and ensure that all calls are coming from DocuSign is to use HMAC Security.
When using HMAC security, each message sent from your DocuSign Connect account includes additional header values, one for each HMAC key you have defined (up to one hundred), which will contain the message body hashed with one of your HMAC keys, using HMACSHA256. For example, if you have defined two keys then two headers, X-DocuSign-Signature-1 and X-DocuSign-Signature-2, will be added. They will contain the message body hashed with your first and second secret keys, respectively.
https://developers.docusign.com/esign-rest-api/guides/connect-hmac

Related

Error "INCORRECT_PASSWORD" in postman console on sending request with Client Certificate

I am consuming PCC API, There are two way by using different URLs:
https://connect.pointclickcare.com/auth/token
https://connect2.pointclickcare.com/auth/token
Both using same haeder and bodey excpet onre thinh that is 2nd URLs need two SSL Authentication.
I am able to consume with 1st URL.
Now I added client certificate to try to consume 2nd URL, however I am facing error and also two less value are being sent in header(Same Request
parameter is being used I only change URL for both request.)
Error: INCORRECT_PASSWORD
Screenshot is attached.
I finally found the problem, Passphrase was not added for Client Certificate being sent with http request. so I added with passphrase and now it worked fine.

AWS API Gateway expects the request URL to be encoded twice

My API is a request that can potentially have spaces in the pathParameters.
/data/{id}/hello/{Some message with a space}.
A sample request would be /data/23/hello/Say%20Hi
My angular code from the frontend encodes the request URL that is sent out to the AWS API Gateway but I get the following error.
`The Canonical String for this request should have been
'GET
/data/23/hello/Sayr%2520Hi`
My API gateway has a velocity template the decodes the parameters using $util.urlDecode()
I'm facing the same problem.
I've been stuck for a day.
If you are using HttpApi it cannot be solved.
Nevertheless, if you use RestApi I managed to make this work.
Specifically, you should use the URL Path Parameters.
You should:
Add a resource containing the /{variable}
Add a Url Path Parameter in the Integration Request Configuration with name variable and mapped from method.request.path.variable
Notice that the solution may depend on the integration type that you are using.
In the screenshot below you can see how I'm redirecting all the received traffic to a NetworkLoadBalancer.
The resource has the variable /{proxy+}, the endpoint URL has the {proxy}, and, in the URL Path Parameters, I've configured the mapping method.request.path.proxy.

Exclude headers from s3v4 signature calculation

We are using an onPrem S3 compatible storage server in an intranet network and we want to expose this intranet url to internet so we used a ReverseProxy with a mapping to the intranet url. When we test the intranet url it works perfectly but when we test the internet url we get the 403 error:
The request signature we calculated does not match the signature you provided. Check your Secret Access Key and signing method. For more information, see REST Authentication and SOAP Authentication for details. (Service: Amazon S3; Status Code: 403; Error Code: SignatureDoesNotMatch; Request ID: 0a440c7f:15cc604b1e2:12d3af:24d; S3 Extended Request ID: null), S3 Extended Request ID: null
After debugging, we found that the proxy modifies the host header used to calculate the signature in order to redirect the request to the intranet url...
So my question is how to supress some headers from the V4 signature calculation using AWS SDK or Boto3 client. or is there a better architecture to expose an onPrem S3 service.
Thanks in advance.
Amir.
There are essentially two solutions to this.
The first one is easier: sign the request for the internal URL, then just use simple string prefix replacement to rewrite the host part of the signed URL to point it to the hostname of the external proxy. When the proxy rewrites the Host header, it will end up rewriting it back to exactly what you signed.
It is, I assume, common knowledge that signed URLs are immune to tampering, for all practical purposes: you can't change anything about a signed URL without invalidating it... but that's not what this is. The change is temporary, and the proxy's net effect is to undo the change.
The alternate solution requires the proxy or another service in the chain (before the storage service) to know the signing keys and secrets, so that it can first validate the incoming request, and if valid, modify the request and then generate a new signature that the service will accept. I once wrote a service to do this so that when a request was for HEAD, the proxy would use the same key and secret (which it knew) to generate a signature for the same request, but with GET. If it matched the signature in the incoming request, the proxy would replace the existing signature with a signature for a HEAD request -- thus allowing the client to use a URL originally signed for a GET request, to make either a GET or a HEAD request -- something S3 does not natively support, since a GET and a HEAD for the same object require two different signed URLs. The concept is the same, though -- generate a signature in the proxy for what the client is requesting, to validate the incoming signature, and then re-sign the request as needed. The solution I built used HAProxy's Lua integration to examine and modify the request in flight.

Getting "EndpointDisabled" from Amazon SNS

I'm using Amazon SNS. Notifications work well, but sometimes I get this error:
{
"message": "Endpoint is disabled",
"code": "EndpointDisabled",
"name": "EndpointDisabled",
"statusCode": 400,
"retryable": false
}
Maybe you know why.
You can create a new SNS topic such as push-notification-failures and then associate your APNS/APNS_SANDBOX applications' "Delivery Failures" event to it. Subscribe to the event via email (and confirm) and you'll get useful debugging information about failures. This can all be accomplished through the SNS console and doesn't require API calls to perform.
It is probably worth it to subscribe an HTTP endpoint to this SNS topic and record all delivery failures so you have historical data to work from and debug production issues.
For example a delivery FailureMessage of "Platform token associated with the endpoint is not valid" means that you're sending a message from APNS_SANDBOX to an APNS registered device or vice versa. This can mean that you have the wrong APNS settings for your build system. (We have a frustrating problem of developer built binaries using APNS_SANDBOX vs. TestFlight built binaries using APNS for local testing and QA which is what led me down this path.)
I have found 3 reasons so far:
Sometimes we mixed tokens from sandbox app.
User turn off notifications in phone settings.
User uninstalled the app.
These are regarding Iphons/Ipads.
There are few reasons why an end point can be disabled. I didn't see it documented anywhere (might have missed it), here's what I got from support:
You push to an endpoint but the token is invalid/expired. Tokens become invalid if:
It belongs to an app that is no more installed on the device.
If device has been restored from backup. This renders token invalid and your app should request a new token and update SNS endpoint token accordingly.
App has been re-installed on the same device. In case of Android, the app is assigned a new token. This happens as well with APNs but more often with Android.
In case of APNs, a wrong provisioning profile is selected in xCode. In this case notifications fail and device becomes disabled later after APNs feedback.
If mistakenly use a token for IOS development to IOS production app and vice versa.
If Apple for any reason invalidates your IOS push cert or someone revokes the push cert from itunes connect portal. This takes a few hours before device gets disabled.
Same with GCM if you update API key from Google developer console without updating the Platform application credentials in SNS.
You push to an APNs device endpoint but application has been disabled due to expired push certificate.
You push to GCM device endpoint however API key has been updated in Google developer console but not the SNS platform application credentials accordingly.
For Details, I recommend this excellent article which solves my problem
According to http://docs.aws.amazon.com/sns/latest/APIReference/API_Publish.html that means that the endpoint is disabled.
From http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/sns/model/SetEndpointAttributesRequest.html:
Enabled -- flag that enables/disables delivery to the endpoint. Message Processor will set this to false when a notification service indicates to SNS that the endpoint is invalid. Users can set it back to true, typically after updating Token.
"notification service" in this case is referring to Google's GCM, Apples APNS or Amazon's ADM.
I had the same issue.
This is what I did:
export the FULL CERTIFICATE from Keychain Access to a .p12 file
export the PRIVATE KEY from Keychange Access to a *private.p12 file
use openssl with the downloaded .cer file (from iOS Developer MemberCenter) to create a public .pem certificate
use openssl with the generated *private.p12 file to create a private .pem keyfile
In AWS SNS create a new Application. Give it a name. Choose Apple Development.
Choose the FULL CERTIFICATE from Keychain Access with a .p12 extension, and type in the passphrase you chose when exporting from Keychain Access
Copy the content of the public CERTIFICATE .pem file, to the textarea labelled "Certificate", including the starting and ending lines:
-----BEGIN CERTIFICATE-----
-----END CERTIFICATE-----
Copy only the part of the private key .pem file starting and ending with the following lines, to the textarea labelled "Private Key":
-----BEGIN RSA PRIVATE KEY-----
-----END RSA PRIVATE KEY-----
I use Cordova with phonegap-plugin-push 1.4.4, but it my issue had nothing to do with phonecap. Apart from a bit of confusion about the above, what finally did the trick for me, was to open up my project in XCode, find the Target for my project, and then enable Push Notifications. This automatically adds the "Push Notifications" entitlement to the app ID.. The next time the app is installed on your device, push notification should work. At least it did for me.
I hope this can save someone experiencing the same issue as me a 1/2 day of work! :)
Quick checklist before taking drastic measures:
Generate the Certificate Signing Request (CSR) using Keychain App.
Export the APNS certificate and its private key into a single p12 file using Keychain App.
When you create a new application in Amazon SNS, the platform must match the APNS environment (Development/Production on both sides).
When you request a device token, you must be in the right application (the application's bundle identifier matches the APNS certificate).
When you create a new platform endpoint in AWS SNS, the device token must be added to the right application (the good application certificate and the good Development/Production platform).
In my case I generated the CSR using a third party SSL tool. I obtained a valid certificate from Apple developer portal but without the private key. Then I tried Windows' certificate tool to export without great success. Waste of time. Start your Mac.
Then I used the AmazonMobilePush sample app to get a device token. Because the demo's bundle identifier doesn't match my certificate, the endpoint was invalid. At each SNS sending the endpoint became disabled (false). At the end the cause was obvious, but I still lose precious time.
If you get the error End Point is Disabled, use the code below to enable the endPoint and then Push Notification using Amazon credentials:
*//Enable Device*
var sns = new AmazonSimpleNotificationServiceClient("AwsAccesskeyId", "AwsSecrteAccessKey", RegionEndpoint.USWest1);
Dictionary<string, string> objDictCheckEndpointEnable = new Dictionary<string, string>();
objDictCheckEndpointEnable.Add("Enabled", "False");
sns.SetEndpointAttributes(new SetEndpointAttributesRequest
{
Attributes = objDictCheckEndpointEnable,
EndpointArn = "AwsEndPointArn" //This is Device End Point Arn
});
*//End*
For me, I was getting the "Platform token associated with the endpoint is not valid" because my SNS Platform Application Endpoints were not set up correctly. Specifically, the SNS console was not reading the credentials correctly from my .p12 file even though it contained the correct cert and private key. The solution, based on this post, was to create a second .p12 file that contained the cert and no key. I loaded the credentials from the first .p12 file, and then loaded the credentials second .p12 file. I could see the cert string change when I did so, and afterward I had no problems.
If you are creating a production endpoint, SNS will warn you about mismatched certs, but it does no such checking for development endpoints. The only way you will know that the endpoint is borked is when you get the platform token error.
I sure hope this helps somebody out there, as it drove me to distraction.
I am using this. If the get endpoint response finds the NotFound error, it creates an endpoint (this should never happen, but hell, it's on AWS SNS documentation website).
If that doesn't happen, it means you're getting the info for the endpoint. It can either be ok (tokens match and enabled is true), or the other way around (in which case you need to update it).
- (void)getEndpointDetailsWithResponse:(void(^)(AWSSNSGetEndpointAttributesResponse *response, AWSTask *))handleResponse {
NSString * deviceTokenForAWS = [self deviceTokenForAWS];
AWSSNS *manager = [AWSSNS SNSForKey:#"EUWest1SNS"];
AWSSNSGetEndpointAttributesInput *input = [AWSSNSGetEndpointAttributesInput new];
input.endpointArn = self.endpointArn;
AWSTask *getEndpointAttributesTask = [manager getEndpointAttributes:input];
[getEndpointAttributesTask continueWithBlock:^id(AWSTask *task) {
NSLog(#"%# Error: %#", task.result, task.error);
AWSSNSGetEndpointAttributesResponse *result = task.result;
NSError *error = task.error;
if (error.code == AWSSNSErrorNotFound) {
[self createEndpointWithResponse:^(AWSSNSCreateEndpointResponse *createResponse) {
dispatch_async(dispatch_get_main_queue(), ^{
if (handleResponse != nil) {
handleResponse(result, task);
}
});
}];
} else {
NSLog(#"response for get endpoint attributes : %#", result);
NSString *token = [result.attributes valueForKey:#"Token"];
NSString *enabled = [result.attributes valueForKey:#"Enabled"];
NSLog(#"token : %#, enabled : %#", token, enabled);
BOOL wasSuccessful = [token isEqualToString:deviceTokenForAWS] && ([enabled localizedCaseInsensitiveCompare:#"true"] == NSOrderedSame);
if (!wasSuccessful) {
NSLog(#"device token does not match the AWS token OR it is disabled!");
NSLog(#"Need to update the endpoint");
AWSSNSSetEndpointAttributesInput *seai = [AWSSNSSetEndpointAttributesInput new];
seai.endpointArn = self.endpointArn;
NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:deviceTokenForAWS, #"Token", #"true", #"Enabled", nil];
seai.attributes = attributes;
AWSTask *setEndpointAttributesTask = [manager setEndpointAttributes:seai];
[setEndpointAttributesTask continueWithBlock:^id(AWSTask *task) {
NSLog(#"response : %#, error: %#", task.result, task.error);
dispatch_async(dispatch_get_main_queue(), ^{
if (handleResponse != nil) {
handleResponse(result, task);
}
});
return nil;
}];
} else {
NSLog(#"all is good with the endpoint");
dispatch_async(dispatch_get_main_queue(), ^{
if (handleResponse != nil) {
handleResponse(result, task);
}
});
}
}
return nil;
}];
}
This is the exact replica of the AWS SNS token management documentation found here: https://mobile.awsblog.com/post/Tx223MJB0XKV9RU/Mobile-token-management-with-Amazon-SNS
I can attach the rest of my implementation if needed, but this part is the most important one.

Bad request error with ruby google-api-client when querying Google Admin Directory API

I am using version 0.6.4 of google-api-client ruby gem to query Google Admin Directory API.
Here is my session in ruby console:
require 'rubygems'
require 'google/api_client'
SERVICE_ACCOUNT_CLIENT_ID = "SOME_STRING.apps.googleusercontent.com"
SERVICE_ACCOUNT_EMAIL = "SOME_STRING#developer.gserviceaccount.com"
SERVICE_ACCOUNT_PKCS12_FILE_PATH = "/path/to/privatekey.p12"
key = Google::APIClient::KeyUtils.load_from_pkcs12(SERVICE_ACCOUNT_PKCS12_FILE_PATH, 'notasecret')
asserter = Google::APIClient::JWTAsserter.new(SERVICE_ACCOUNT_EMAIL, "https://www.googleapis.com/auth/admin.directory.device.chromeos.readonly", key)
client = Google::APIClient.new
client.authorization = asserter.authorize
dir_api = client.discovered_api('admin', 'directory_v1')
resp = client.execute(:api_method => dir_api.chromeosdevices.list, :parameters => {'customerId'=>SERVICE_ACCOUNT_CLIENT_ID})
resp.body
=> "{\n \"error\": {\n \"errors\": [\n {\n \"domain\": \"global\",\n \"reason\": \"badRequest\",\n \"message\": \"Bad Request\"\n }\n ],\n \"code\": 400,\n \"message\": \"Bad Request\"\n }\n}\n"
I am probably missing something obvious here but it is unclear from the error response what is missing in the request. Would appreciate any help/pointers in the right direction.
Thanks.
I got a similar response in my C# program, listing users in my domain.
I still haven't resolved it but so far I managed to get the same error message in
The APIs Explorer https://developers.google.com/apis-explorer/#p/admin/directory_v1/
when trying to do the same request there and omitting any value for domain.
That led me to believe that I somehow needed to add the domain to my request in my C#-code and by trial and error I THINK I found how to do it in C#.
But my suggestion is to try your API request in the APIs Explorer and then se if you could get the same error message there by NOT submitting the value for domain, as I think that's what the error-message means.
I've had the same problems. I've wrote an example gist which explains how to set it up:
https://gist.github.com/thomaswitt/7468182
Steps are:
Go to Google Cloud Console (https://cloud.google.com/console)
Create Service Account with P12 File
Enable the Admin SDK in APIs.
Create a Project
Create a registered app within this project
Go to section 'Certificate' and generate a key
Download the JSON file as well
Go to the Apps Console > Security > Extended > 3rdPartgy OAuth
(https://admin.google.com/AdminHome?#OGX:ManageOauthClients)
Add an API Client. Client name is value of client_id in the JSON
file, API Scope is https://www.googleapis.com/auth/admin.directory.user.readonly
I found that #JoBe's answer was pretty much on track. In Ruby, using the Google-Api-Client gem, you need to pass a hash to list_users, with the domain. i.e.
UserService.list_users(domain: 'mydomain.com').