I'm looking to access SmugMug's API from my application to grab users' albums and images (the users have been authenticated via ruby's OmniAuth).
According to SmugMug's OAuth API, OAuth requires six parameters.
I can get the token with OmniAuth, and the timestamp should be easy (Time.now.to_i right?). There are two things that I don't know how to generate -- the oauth_nonce and the oauth_signature.
According to the oauth docs, I generate the nonce via the timestamp, but how exactly would I do that? Does it need to be a certain length and limited to certain characters?
And of course the signature. How would I generate a HMAC-SHA1 sig with ruby? I know the oauth gem can do it, but I'd rather generate it myself to use with OmniAuth. Looking at the code, I'm having trouble deciphering how the oauth gem generates the sig.
Thank you for any help.
For the signature:
def sign( key, base_string )
digest = OpenSSL::Digest::Digest.new( 'sha1' )
hmac = OpenSSL::HMAC.digest( digest, key, base_string )
Base64.encode64( hmac ).chomp.gsub( /\n/, '' )
end#def
You don't have to generate the nonce from the timestamp, but it can make sense since the timestamp is obviously unique, so it makes a good starting input for any randomisation function.
I use this, (that I got from another question on here and modified)
def nonce
rand(10 ** 30).to_s.rjust(30,'0')
end#def
but you can use anything that generates a unique string.
See this gist by erikeldridge on github and Beginner’s Guide to OAuth for more
Edit
I've since found there's a better way to generate random strings in the Ruby standard library, SecureRandom.
A nonce can also be simply a large-ish, properly random number - for example, using Ruby's SecureRandom class (don't use 'rand'):
require 'securerandom'
...
nonce = SecureRandom.hex()
This generates a 16-byte random number in hex format.
Why you don't just use the Oauth ruby gems to do that ?
Related
I'm looking to generate a unique key/token for my Invites model. Example usage:
mysite.com/invites/XXXXXX
Where XXXXXX is the unique key/token... I'm using Rails 5 for my API and learned Rails 5 has a new way to generate a secure token like so:
Model
has_secure_token :access_token
The current Rails method creates a very LONG, unfriendly token: 973acd04bc627d6a0e31200b74e2236
My question: Does the token really need to be that long for a model like Invites which expire, meaning tokens are not permanent. Ideally I believe the UX is better with a shorter length token so the token doesn't appear like a bug to a user.
Does anyone know of any recommendations on token length for non-permanent tokens like invite URLs?
Does the token really need to be that long
Well it doesn't always need to. Normally in Rails we use SecureRandom to generate such unique tokens. You can always get the tokens of desired length like below and use those.
SecureRandom.hex(10) # => "52750b30ffbc7de3b362"
SecureRandom.hex(3) #=> "71edbe"
I want to send a bcrypt hash with random hash as a URL parameter. For example
hash=$2y$10$SWNoIGJpbiBkYXMgU2Fsd.t/I3wS/nUqo5eRQp8b7oakL/kQlZ5da
So my questions are:
Is this a good idea or should I remove the salt from the hash? How can I do this? Is the first dot every time the delimiter?
You really shouldn't be putting someone BCrypt'd password out on the wire. Even though BCrypt is hard to brute-force; it's better to not make it easier for someone to get ahold of it.
I suggest, as user33888366 did, that if you need a kind of security token, use the HMAC of values in the url.
Read Life in a post-database world: using crypto to avoid DB writes for examples of using crypto to trust your urls.
Short version
http://myapp.com/resetPassword?userId=johnnysmith&expirationTime=1356156000&token=%SECURITYHASH%
where %SecurityHash% is the HMAC hash of:
userId
reset expiration time
bcrypt hash
When the URL comes it, parse it:
userId=johnnysmith&expirationTime=1356156000&token=%SECURITYHASH%
^^^^^^^^^^^ ^^^^^^^^^^
and recalculate the HMAC of:
johnnysmith
1356156000
johnnysmith's bcrypt hash
if it matches the passed security token, you know you have a valid request.
I'm using SagePay's form integration method with a Ruby on Rails/EmberJS app. I'm handling all the complex payment construction in Rails.
In short, SagePay needs an encrypted, encoded 'crypt' string, which contains data such as the user's billing address, the amount, post-payment redirects, and other transaction data.
SagePay gives an encryption password in the test environment. The form integration guide says to build the crypt as a string, then encrypt it using AES-256 and the encryption password, then Base64 encode the string for POSTing to the Sage test payments server.
Here's how I've implemented this (using the Encryptor gem):
def encryptandencode(string)
salt = Time.now.to_i.to_s
secret_key = 'test-server-secret-key-from-sage'
iv = OpenSSL::Cipher::Cipher.new('aes-256-cbc').random_iv
encrypted_value = Encryptor.encrypt(string, :key => secret_key, :iv => iv, :salt => salt)
encoded = Base64.encode64(encrypted_value).encode('utf-8')
return encoded
end
where string is the unencoded, unencrypted Crypt string containing transaction data.
The problem
Encryptor refuses to use the given secret key. It says the key is too short.
What am I missing here?
I'm struggling to do the same thing in ASP.NET. I don't know why the example 'Integration Kits' they give you on the website are so complicated. They may represent elegant pieces of code in themselves, but they obfuscate how things are working by having functions call functions call methods using settings in the web.config file. For developers new to this API a simple example with all the code in one place would be helpful.
ANYWAY, I still haven't got it working but I have managed to overcome the problem you're having, though my method may not help you since I'm working in ASP.NET. I added a reference to the SagePay.IntegrationKit.DotNet.dll to my project, after which I was able to call the function
SagePay.IntegrationKit.Cryptography.EncryptAndEncode(<name=value collection>, <Encryption Password>)
I now appear to get a valid encrypted string to send to SagePay, my problem is that their website says the encryption is wrong, so this is still a work in progress.
I was struggling with this too, and receiving the same error message.
I finally decided to try each line from the Encryptor gem directly and no longer received that error message. Therefore I have ditched that gem from my Gemfile.
BTW, you have a few things wrong in your example:
you need to use 128 bit encryption, not the default 256: :algorithm => 'aes-128-cbc'
the initialisation vector needs to be the same as the key: :iv => secret_key
you mustn't use a salt
the result needs to be hex encoded not Base64
result = encrypted_value.split('').map { |c| "%02X" % c.ord }.join
The Test and Live Encryption password differ also check your encryption password is 16 characters in length.
Sage Pay Support
E.g. API_key: 4faa86aa5848207502000002 and API_secret 7375d7d1e89d3d602b184432fbcf3c09c7cb30676f19af9ac57d228be401.
Should I use SecureRandom?
Thanks!
ActiveSupport::SecureRandom would work for the actual generation, but you should also consider a way to invalidate and reset the token on different events.
Since you're using Devise, take a look at the Token Auth Strategy. You could write a similar strategy with two tokens (API Key and API Secret, respectively). You need to write both the strategy and the Model, but in both cases the Token Auth example gets you pretty far.
As a starting point (from the Token Auth example), your model should declare both required parameters.
module Devise
module Models
module APIKeyAuthenticatable
...
def self.required_fields(klass)
[:api_key, :api_secret]
end
def reset_keys
self.api_key = self.class.api_key
self.api_secret = self.class.api_secret
end
You might also want to read Custom authentication strategy for devise. If you're looking to provide a more full-featured API auth solution atop devise devise_oauth2_providable looks pretty good.
I have tried authlogic_api. It was fairly easy to implement.
This is my first attempt at writing a Rails app to consume an external web service.
I have done some basic experimentation retrieving some records from another rails app via ActiveResource which worked pretty well, but in this instance I am trying to access a third party web service which requires very specific authentication before I can do anything.
The service in question is a REST API provided by DNSMadeEasy the documentation for which can be located at http://www.dnsmadeeasy.com/services/rest-api/
The authentication requirements according to the documentation are as follows:
Create the string representation of the current date and time in HTTP format. Example:
Sat, 12 Feb 2011 20:59:04 GMT
Calculate the hexadecimal HMAC SHA1 hash of that string using your Secret key as the hash key.
Set the values for the request headers using your API key, the current date and time, and the HMAC hash that you calculated.
So I figured out how to get the date and calculate the hash:
request_date = Time.now.httpdate
hmac = OpenSSL::HMAC.hexdigest('sha1', secret_key, request_date)
So my question has three parts:
Firstly, how do I then go about inserting this information in the HTTP header when I send off my request to the web service?
Secondly, how do I go about putting all this in a super class that my ActiveResource classes inherit from, so that I don’t have to worry about it in the classes for Domain and ResourceRecord?
Thirdly, is there a best practice for storing API and secret keys in your app, i.e. should this be done with an initializer, or is it best to use an environment variable?
Any tips and tricks for this sort of workflow would be extremely appreciated.
Thanks
1 - You can set the headers by setting an instance variable called #headers like this:
class Base < ActiveResource::Base
#headers = { ‘key’ => ‘value’ }
end
Take a look at the source Active Resource: Headers
2 - Make all your resources inherit from that Base that you just created instead that making them inherit from ActiveResource::Base.
3 - I usually put those keys in environments files or I use this gem SettingsLogic