Best way to store a user token in Ruby script - ruby

I am developing a Ruby script designed for CLI which is based on a REST API. This API needs a token as credentials in order to recognize the user and allows him to retrieve his informations.
For now, this scripts asks the 30-length token in the console every time it is launched.
Now I'd like to store this token to avoid asking it every time the user wants to use the script. I don't know what the best way is, do I have to create a hidden file, containing the token, or ask the user to store it in an environment variable ?
I wanted to use the environment variable solution, but I don't know if it will work the same way for Windows or Linux.

Compose all approaches. Something like this:
def get_my_token()
if ENV["MY_TOKEN"]
return ENV["MY_TOKEN"]
end
token_path = File.expand_path("~/.my_token") # will be expanded to user's home (Documents or smth) in windows, check it yourself as I don't have running windows around here
if File.exists?(token_path)
return File.read(token_path).strip
end
# resort to asking user for token here
end
ENV should go first - so you'll be able to override your config if needed for some testing purpose. Also note that you can run your script as MY_TOKEN=xxxx ruby my_app.rb as well.

Related

I would like to create some kind of API to run a ruby program via a unique key

I wrote a ruby program that runs on my local machine, and I want to turn it into a linux server API that will send back the formatted JSON file that the ruby program generates. The ruby program already works, and generates a separate JSON file on my local machine, but I would like to turn it into an API that returns the generated JSON from the program on request. The API should accept a single key, and run the program based on that key. How can I do this? What is it called that I am trying to accomplish? Thank you for any help you can provide.
Here is a VERY basic example of how easy this is to do using Sinatra which is good for such simple type of web applications / APIs.
If we assume your current program already renders the json to a static file, for example.
sample.json
[
{
"item1": {
"foo": "bar"
},
"item2": {
"baz": "qux"
}
}
]
On your linux system you should have some secure random key set. You can do that also with one liner assuming ruby is installed.
ruby -e 'require "SecureRandom"; puts SecureRandom.hex(32)'
Or in pure linux
date +%s | sha256sum | base64 | head -c 64 ; echo
Then in your server's startup scripts you'll need to make sure to export the key.
export API_KEY=ODAzN2EzMmI2YTc2ZDIzZjA5NzRmYmJiNjJjYmE4OGUyYjVjMDM0ZWJkZWU4NmMz
Then in same path as your json file, write a file called api.rb
# api.rb
require 'sinatra'
get '/api' do
if params['key'] == ENV['API_KEY']
return File.read 'sample.json'
else
status 401
end
end
By default Sinatra runs on port 4567 so you'll need to expose it on your server which seems outside the scope of your Ruby question.
Depending on how and where you host this, you'll want to configure your server to run the application at startup. For your local development you can just run this from terminal.
ruby app.rb
To see it working just visit
http://localhost:4567/api?key= # <<-- paste your key here.
Also, keep in mind, there is no security besides the key here and this will be subject to brute force attacks, but again, that's also outside the scope of this question.
UPDATE
If you need to support multiple users with their own keys, you'll need more complex logic and likely use a database to store the user information. API keys alone may not provide enough security if your api is serving sensitive information. So you'll probably want to add more layers of security. You still could build this using Sinatra, but you might want to go with Ruby on Rails to build your API instead.

How can I authorize a Google Service Account without the default credentials file?

I have a Google Service Account that my app uses to retrieve data from Google Analytics.
When I created the account I downloaded a client_secrets file with all the necessary information for authorization via OAuth, and I recorded the path to this file in an environment variable called GOOGLE_APPLICATION_CREDENTIALS as per Google's documentation.
I can now get an authenticated client like this:
authorization = Google::Auth.get_application_default(scopes)
This method reads the credentials out of the file, which works locally, but my app is hosted on Heroku where file storage is impossible.
The documentation states that I can either provide this file (can’t), run my app on an official Google Service (won’t), or experience an error.
How can I authenticate my service account without the client_secrets file?
I found the answer in the source code of the google-auth-library-ruby gem.
It turns out that there is another option: take the values from the client_secrets file and put them in environment variables named GOOGLE_ACCOUNT_TYPE, GOOGLE_CLIENT_ID, GOOGLE_CLIENT_EMAIL and GOOGLE_PRIVATE_KEY respectively.
If these keys are populated, the credentials will load from there. Not a whisper of this in the docs, though.
Since this is one of the main results that returns when searching google for "google service credentials ruby," I thought I would add my very recent experience to the list of possible answers.
Though you can do the method mentioned in the first answer, I found an alternate solution that works well with Heroku. I know it has been somewhat mentioned in another post, but the key thing that was left out was how to properly store the full GOOGLE_APPLICATION_CREDENTIALS .json file so that it can all be kept within one env on Heroku and not have special characters blow up your app when tryin to
I detail my steps below:
Obtain your GOOGLE_APPLICATION_CREDENTIALS json file by following Google's instructions here: Getting Started with Authentication
That will, of course, contain a json object with all the spaces, line returns, and quotations that heroku simply doesn't need. So, strip out all spaces and line breaks...AND PAY ATTENTION HERE -> EXCEPT FOR THE LINE BREAKS WITHIN THE 'BEGIN PRIVATE KEY' SEGMENT. Basically turn the json into one long string. Use whatever method you feel comfortable with.
Once you have a single line json file with whitespace and line breaks removed, you will need to add it to Heroku by running the following command:
heroku config:set GOOGLE_APPLICATION_CREDENTIALS="$(< /Users/whoever/Downloads/[CREDENTIAL_JSON_FILENAME].json)" --app your-app
For my situation, I needed to have the service account available on initialization, so I placed this in an initializer in my rails app:
GOOGLE_SERVICE_ACCOUNT_CREDENTIALS=Google::Auth::ServiceAccountCredentials.make_creds(
json_key_io: StringIO.new(ENV['GOOGLE_APPLICATION_CREDENTIALS'])
)
Notice the StringIO.new() method. the #make_creds wants a file. So, fake it as such by using StringIO.new.
This method works perfectly.
If you need this to work differently on your local machine, you can always store the .json somewhere in the project and reference it through a file location string. Here is my full initializer:
require 'googleauth'
#https://www.rubydoc.info/github/google/google-auth-library-ruby/Google/Auth/ServiceAccountCredentials
if Rails.env == "test"
GOOGLE_SERVICE_ACCOUNT_CREDENTIALS =
Google::Auth::ServiceAccountCredentials.make_creds(
json_key_io: File.open('lib/google/google_application_credentials.json')
)
elsif Rails.env != "development"
GOOGLE_SERVICE_ACCOUNT_CREDENTIALS =
Google::Auth::ServiceAccountCredentials.make_creds(
json_key_io: StringIO.new(ENV['GOOGLE_APPLICATION_CREDENTIALS'])
)
end
If you are using a gem like dotenv you can store the formatted json string as an ENV or you can just reference the file location in the ENV
I hope this helps someone.
I found this
require "google/cloud/bigquery"
ENV["BIGQUERY_PROJECT"] = "my-project-id"
ENV["BIGQUERY_CREDENTIALS"] = "path/to/keyfile.json"
bigquery = Google::Cloud::Bigquery.new
more detail:
https://github.com/googleapis/google-cloud-ruby/blob/master/google-cloud-bigquery/AUTHENTICATION.md

Passing variables on the command line to a Cucumber test

I'm trying to keep usernames and passwords for a cucumber project out of version control.
Is there a way to manually pass variables on the command line like usernames and passwords to a cucumber script?
My backup plan was to put them in a YML file and add that file to the gitignore so they aren't put in version control.
So, I saw your comments with the Tin Man, and answer is Yes.
cucumber PASSWORD=my_password
PASSWORD is set as an environment variable and you can use its value by referring to it as ENV['PASSWORD']. For an example, browser.text_field(:id => 'pwd').set ENV['PASSWORD']
Another way is indirect.
What I did in past was to pass profile name and that profile will do something that I want. So, for example, I have a profile name as firefox and a firefox profile in cucumber.yml has a variable named BROWSER_TYPE with its value assigned to firefox. And this variable (BROWSER_TYPE) is used by my method that opens the browser. If its value is firefox, than this method opens firefox browser.
So, what I did here was -
Pass a profile. Name of the profile is firefox
firefox profile is defined in cucumber.yml. You can any thing with the profiles, but in this case, I define a variable named BROWSER_TYPE and assign its value as firefox.
Then I have a method that uses BROWSER_TYPE variable and uses its value to open browser.
Code for these steps -
cucumber -p firefox
My cucumber.yml file looks like
firefox: BROWSER_TYPE=firefox PLATFORM=beta
My method to open browser looks similar to -
#browser = Watir::Browser.new ENV['BROWSER_TYPE']
So, ideally you can create a profile that sets an environment variable with password, and pass that profile name to cucumber.
Two thoughts:
1) I've had the same concern, and I created some shell scripts (Mac an Unix) that store credentials in a directory off ~ that are encrypted with machine-specific passwords. I can then use "Given the credentials named blah" in my Cucumber scenarios and then use #username = testcred get #{credname} username #username = testcred get #{credname} password in my step definitions to make this work with no chance that my credentials are ever anyplace they could mistakenly get into a repo. See https://github.com/usethedata/credstore.git for where I've put this into github (early work)
2) Lastpass has a command line version that works. I've also played with sharing my test credentials with a LastPass account that's used for just test credentials. I've used the credstore stuff above to store the lastpass master password for that account (never for my real master password) and then used the lastpass command line to get the usernames and passwords. This has the advantage of when I change the credentials in Lastpass, they get updated automatically everywhere they're used

Ruby Test script structure advise

I am writing an automated test suit for a program that has mailing lists. I am trying to decide on the best practice for structuring the tools that I am going to use. The tests need to send email to a variety of email addresses then use the application to perform an action (approve, reject, discard). Then the script finally needs to check its mail and compare the email it has received against the list of emails it expects to receive. Here is the list of tools I am using.
Ruby,
Rake,
Selenium Webdriver,
Test-unit,
Jenkins
What I wanted to do was to treat everything as a dependency (in rake) of the last step(checking the email). My problem came when tried to make every email unique. I plan to embed the time the test was run at and a number assigned to each email in the test into the email (this number will be the same for each run of the test so I can identify where it should go). I need a way to pass the time stamp from the beginning of the test to the end of the test.
The solutions I see to my problems are to get rid of rake (because I can't or don't know how to pass a variable between tasks) or to write to a file then access the file in the seperate tasks.
Any recommendations?
I would advise setting an ENV variable in your Rakefile before each test is run, like this:
ENV['TIMESTAMP_CONTROL'] = Time.now.to_s
You can then reference the variable anywhere in your scripts and Rakefile until you reset it again like any other Ruby variable:
assert_equal ENV['TIMESTAMP_CONTROL'], #email_response_text

Can this be done? Bash script in a web application

I have a bash script (supports linux/unix), that installs an application.
Instead of executing the script in the terminal, I want to deploy it as a web application.
I want to make a web graphical interface for this script, so that the user can give the necessary inputs in the web forms and when ready,then pass these variables into the bash script to be executed.
This script obvious needs root privileges.
I plan to make it with with tomcat 7 / servlet / jsp. I want to deploy it as .war file.
First, can this be done? Is it possible?
Second, is there any example? I didn't find anything.
Third, any alternative method/better idea?
I'd try tomcat's own CGI support.
http://tomcat.apache.org/tomcat-6.0-doc/cgi-howto.html
Well, it's possible, but keep in mind that sanitizing user input is hard.
What you want to do is use a scripting language or framework (I recommend sinatra), and use a html form to pass arguments to the backend. In the backend, you call your script by passing whatever arguments you want.
Example with sinatra:
post '/whatever' do
# This is dangerous!
`myscript #{params[...]}`
end
Err, but you want this to run on the client side, right?
So you don't really run it as bash on your system, you just template it within your web framework.
If the browser can then display this, it won't just d/l as a file, so you will need to set up a Content-Disposition: attachment header in the response to force a d/l.
You will naturally need the user's cooperation to run this as root on his or her system...

Resources