Ruby on Rails passing a salt to Digest::SHA512 - ruby-on-rails-3.1

what is the equivalent in Rails of this (PHP):
hash_hmac('sha512', $password . $salt, $siteSalt);
I got as far as this:
Digest::SHA512.hexdigest(password + salt)
But have no idea how to incorporate the site salt into the equation, all online examples I've seen do not pass the salt to the hexdigest method. When I've tried it I get an error for too many arguments.
And this notation with a colon (which I saw somewhere):
salted = password + salt
Digest::SHA512.hexdigest("#{salted}:site_salt")
Doesn't produce the same hash.
Thanks
Edit
I stumbled upon this that looks closer to what I need (sorry, I'm very new to the whole hashing thing):
OpenSSL::HMAC.hexdigest('sha512', site_salt, salted)
But it still produces a different hash than the one stored in the database.

I'm using Rails 4 and #brian's rails code didn't compile for me.
Here is what worked for me.
Rails shell:
2.1.2 :001 > Digest::HMAC.hexdigest("password"+"salt","siteSalt",Digest::SHA512)
=> "15b45385a00b10eb25c3aa8198d747862575a796a89a6c79b5a0b8ea332a8d75b1ec0dc1f0c9f7930d30c9359279e86df29067bbbc5d9bcf87839f855ac7a677"
PHP (from command line)
$ php -r 'print hash_hmac("sha512", "password" . "salt", "siteSalt") . "\n";'
15b45385a00b10eb25c3aa8198d747862575a796a89a6c79b5a0b8ea332a8d75b1ec0dc1f0c9f7930d30c9359279e86df29067bbbc5d9bcf87839f855ac7a677

I think this will do what you want:
HMAC::SHA512.hexdigest(site_salt, password + salt)
It looks like the PHP code you're referencing is using the siteSalt as the key for the HMAC function, with the password and salt concatenated specified as the value to be hashed.
I checked this by running this code in PHP:
% php -r 'print hash_hmac("sha512", "password" . "salt", "siteSalt") . "\n";'
15b45385a00b10eb25c3aa8198d747862575a796a89a6c79b5a0b8ea332a8d75b1ec0dc1f0c9f7930d30c9359279e86df29067bbbc5d9bcf87839f855ac7a677
And then in the Rails shell:
>> HMAC::SHA512.hexdigest('siteSalt', 'password' + 'salt')
=> "15b45385a00b10eb25c3aa8198d747862575a796a89a6c79b5a0b8ea332a8d75b1ec0dc1f0c9f7930d30c9359279e86df29067bbbc5d9bcf87839f855ac7a677"

It turns out the salt was empty in the PHP code, hence the discrepancy. But now both methods return the same.

Related

Ruby OpenURI FTP not working when username has spaces

I am using Ruby 1.9.3 and am running the following command:
open("ftp://user name:password#datafeeds.domain.com/1234/1234.txt.gz")
which returns:
URI::InvalidURIError: bad URI(is not URI?)
Encoding the user name (replacing spaces with %20) does not work either:
Net::FTPPermError: 530 Invalid userid/password
The URI works fine in all browsers and FTP clients tested - just not when using OpenURI. Also, using Net::FTP (which is wrapped by OpenURI) works fine as well:
require 'net/ftp'
ftp = Net::FTP.new
ftp.connect("datafeeds.domain.com", 21)
ftp.login("user name", "password")
ftp.getbinaryfile("/1234/1234.txt.gz")
Any idea why the OpenURI method does not work, while the Net::FTP method does? Thanks.
By definition in the specification, URL user names only allow these characters:
user alphanum2 [ user ]
[...]
alphanum2 alpha | digit | - | _ | . | +
Browsers are notorious for ignoring the specifications so saying they support it isn't a good proof. They shouldn't per the spec.
If cURL supports them, then use the Curb gem and see if that'll let you use them.
According to this StackOverflow answer, you should be able to just escape the special characters in your username and password. You could do something like:
login = URI.escape('user name') + ':' + URI.escape('password')
open("ftp://#{login}#datafeeds.domain.com/1234/1234.txt.gz")
open-uri seems broken in that matter. I had the similar issue with the password which contained # character.
I ended up bypassing set_password, which doesn't allow # char in password, by setting URI's #password instance variable directly.
uri = URI.parse(...)
if uri.password
uri.instance_variable_set "#password", "password_with_#_char"
end
open(uri) # now this works fine
It's hacky, but does the job.

How do I get OpenSSL style salted MD5 in Ruby?

I'm talking about this:
$ openssl passwd -1 -salt thesalt thepassword
$1$thesalt$HAWpBmvUCutuyTS4JwevI.
In PHP it would look like this:
crypt('thepassword', ('$1$'.'thesalt')); # this gives the same output as above
I'm trying to achieve the same format in Ruby 1.9. I've been told Ruby's String#crypt will do this but it does not. I've looked everywhere for an answer, but I've come across nothing.
If it helps anything, I'm trying to do this on Windows XP.
Ruby version: ruby 1.9.3p0 (2011-10-30) [i386-mingw32]
Just to keep away the comments telling me to use something other than MD5 or whatever else, I would if I could. This choice isn't up to me.
Thanks.
Edit: I want to do this without shelling out to openssl because that would be too slow for what I need.
If all else fails, you could call the openssl executable using backticks:
password = "thepassword"
salt = "thesalt"
hashed = `openssl passwd -1 -salt #{salt} #{password}`
puts hashed # => $1$thesalt$HAWpBmvUCutuyTS4JwevI.
Darn. I was hoping for the same thing.
see also Generate openssl password with Ruby for the reason why it is not in ruby.

Using ruby to generate SHA512 crypt-style hashes formatted for /etc/shadow?

I want to generate SHA512 hashed passwords for inclusion directly into a /etc/shadow file for use with chef's user resource. Normally I'd go to the stdlib's Digest library for this, but it doesn't generate the hash in the right format:
ruby-1.9.2-p136 :001 > require 'digest/sha2'
=> true
ruby-1.9.2-p136 :002 > Digest::SHA512.hexdigest('test')
=> "ee26b0dd4af7e749aa1a8ee3c10ae9923f618980772e473f8819a5d4940e0db27ac185f8a0e1d5f84f88bc887fd67b143732c304cc5fa9ad8e6f57f50028a8ff"
The format that the shadow file wants is:
$6$/ShPQNXV$HJnibH9lw01qtYqyJQiBf81ggJB2BGUvKA7.kv39HGCeE.gD4C/SS9zAf5BrwOv3VJzvl99FpHYli9E8jykRC0
Things I've looked at:
The openssl "dgst" module returns the same format as .hexdigest, and its "passwd" module doesn't include SHA512 support.
String#crypt, but that does not support SHA512. (edit: this is only the case on OSX - modern Linux distros will work if you specify "$6$somesalt" as the salt)
ruby-crypt gem, but it does not support SHA512
For comparison, something that does return the proper format is PHP's crypt, but I'd rather not have to exec out to PHP for something that should be simple.
After further research:
The mkpasswd command, which on debian is in the whois package (weird):
mkpasswd -m sha-512
String#crypt does actually call the platform's native crypt() call, however OSX (up to 10.6) does not include support for alternate ciphers. "password".crypt('$6$somesalt') will work on Linux platforms.

Adding files to redmine via command line

We have an automatic build system that spits out packages, regression-tested & wrapped into a neat installer, ready for end-users to d/l & deploy.
We do tracking of end user support requests/bug reports via redmine. So far we uploaded the packages manually to the resp. 'Files' section of the redmine project, via the web interface.
What I'd like to do is to automate this step.
I imagine this would requires a few lines of Ruby to interface with redmine's db. I have zero knowledge about redmine's internals. :)
Basically I want the equivalent of a
mv package-x.y.z.tbz /usr/local/redmine/files/
as a Ruby (or whatever language suits the need) script that creates the right filename and registers the file in redmine's db so it shows up as if it had been uploaded through the Web interface, manually.
Cheers!
I've been frustrated with Redmine about things like this before. But before I go much further: is there a specific reason why you're using the Files section for this? It seems another tool (such as SSH/SFTP for uploading to someplace accessible to HTTP) might be a better fit for your needs. It would also be easily scriptable. Just point people to some constant URL like http://yourcompany.com/productname-current.zip.
If you really need to use Redmine for managing this, you might check out Mechanize: http://mechanize.rubyforge.org/. They should have a RESTful API also, but I've never used it.
I found this post, hope it can help you
Automating packaging and RedMine
I'm a bit late, but I've wrote a Redmine upload tool in Perl, using the WWW::Mechanize module.
Please find it on http://github.com/subogero/redgit
As already stated, you can use Mechanize for that.
There's a Python script written by Gert van Dijk's: https://github.com/gertvdijk/redmine-file-uploader
To use it you'll have to install Python Mechanize package first:
easy_install mechanize
If you prefer Ruby, you can use:
require 'mechanize'
# Replaces \ with / and removes "
ARGV.map!{|a|a.gsub('\\','/').gsub(/^"(.+)"$/,'\\1')}
filename = ARGV[0] || abort('Filename must be specified')
puts "File: #{filename}"
url = ARGV[1] || abort('Redmine URL must be specified')
puts "Redmine URL: #{url}"
username = ARGV[2] || abort('Redmine username must be specified')
puts "Username: #{username}"
password = ARGV[3] || abort('Redmine password must be specified')
puts "Password: #{'*' * password.length}"
project = ARGV[4] || abort('Redmine project must be specified')
puts "Project: #{project}"
login_page_path = '/login'
files_page_path = '/projects/' + project + '/files'
agent = Mechanize.new
# No certificate verification (I had to use this hack because our server is bound to custom port)
# agent.agent.http.verify_mode = OpenSSL::SSL::VERIFY_NONE
agent.get(URI.join(url, login_page_path)) do |login_page|
login_page.form_with(:action => login_page_path) do |login_form|
login_form.username = username
login_form.password = password
end.submit
end
agent.get(URI.join(url, files_page_path + '/new')) do |upload_page|
upload_page.form_with(:action => files_page_path) do |upload_form|
upload_form.file_uploads.first.file_name = filename
end.submit
end
And don't forget to install gem first:
gem install mechanize

Equivalent of cURL for Ruby?

Is there a cURL library for Ruby?
Curb and Curl::Multi provide cURL bindings for Ruby.
If you like it less low-level, there is also Typhoeus, which is built on top of Curl::Multi.
Use OpenURI and
open("http://...", :http_basic_authentication=>[user, password])
accessing sites/pages/resources that require HTTP authentication.
Curb-fu is a wrapper around Curb which in turn uses libcurl. What does Curb-fu offer over Curb? Just a lot of syntactic sugar - but that can be often what you need.
HTTP clients is a good page to help you make decisions about the various clients.
You might also have a look at Rest-Client
If you know how to write your request as a curl command, there is an online tool that can turn it into ruby (2.0+) code: curl-to-ruby
Currently, it knows the following options: -d/--data, -H/--header, -I/--head, -u/--user, --url, and -X/--request. It is open to contributions.
the eat gem is a "replacement" for OpenURI, so you need to install the gem eat in the first place
$ gem install eat
Now you can use it
require 'eat'
eat('http://yahoo.com') #=> String
eat('/home/seamus/foo.txt') #=> String
eat('file:///home/seamus/foo.txt') #=> String
It uses HTTPClient under the hood. It also has some options:
eat('http://yahoo.com', :timeout => 10) # timeout after 10 seconds
eat('http://yahoo.com', :limit => 1024) # only read the first 1024 chars
eat('https://yahoo.com', :openssl_verify_mode => 'none') # don't bother verifying SSL certificate
Here's a little program I wrote to get some files with.
base = "http://media.pragprog.com/titles/ruby3/code/samples/tutthreads_"
for i in 1..50
url = "#{ base }#{ i }.rb"
file = "tutthreads_#{i}.rb"
File.open(file, 'w') do |f|
system "curl -o #{f.path} #{url}"
end
end
I know it could be a little more eloquent but it serves it purpose. Check it out. I just cobbled it together today because I got tired of going to each URL to get the code for the book that was not included in the source download.
There's also Mechanize, which is a very high-level web scraping client that uses Nokogiri for HTML parsing.
Adding a more recent answer, HTTPClient is another Ruby library that uses libcurl, supports parallel threads and lots of the curl goodies. I use HTTPClient and Typhoeus for any non-trivial apps.
To state the maybe-too-obvious, tick marks execute shell code in Ruby as well. Provided your Ruby code is running in a shell that has curl:
puts `curl http://www.google.com?q=hello`
or
result = `
curl -X POST https://www.myurl.com/users \
-d "name=pat" \
-d "age=21"
`
puts result
A nice minimal reproducible example to copy/paste into your rails console:
require 'open-uri'
require 'nokogiri'
url = "https://www.example.com"
html_file = URI.open(url)
doc = Nokogiri::HTML(html_file)
doc.css("h1").text
# => "Example Domain"

Resources