Omniauth authentication fails in Rails 4 - ruby

I am working in rails 4 and I am trying to authenticate using github. So in my Github application I have this:
URL: http:// localhost:4000
Callback URL: http:// localhost:4000/auth/github/callback
The callback url is the url that Github will try to reach when the authentication is done right?
So why do I get a Github page 404 error when I click on my link:
<%= link_to 'Sign in with Github', '/auth/github' %>
I am working on a localhost development enviroment so that might be the problem?
Also when i type http:// localhost:4000/auth/github/callback on my browser I get an OmniAuth::Strategies::OAuth2::CallbackError
why? I have this in my routes.rb
post 'auth/:provider/callback' => 'home#index'
Is Rails 4 and Omniauth bugged?
(added the space in localhost so stackoverflow accepts my post)

I have github working with the gem omniauth-github
and a file config/initializers/omniauth.rb containing
Rails.application.config.middleware.use OmniAuth::Builder do
provider :github, ENV['GITHUB_KEY'], ENV['GITHUB_SECRET']
end
However, when I enter http://localhost:3000/auth/github/callback on my browser I also get OmniAuth::Strategies::OAuth2::CallbackError so this shouldn't be the problem.
My config/environment.rb looks like
# Load the rails application
require File.expand_path('../application', __FILE__)
# Load the app's custom environment variables here, so that they are loaded before environments/*.rb
app_environment_variables = File.join(Rails.root, 'config', 'app_environment_variables.rb')
load(app_environment_variables) if File.exists?(app_environment_variables)
...
and my config/app/environment_variables.rb looks like
# OAuth Keys and Secrets
if Rails.env.production?
ENV['GITHUB_KEY'] = 'd1234a3a123a1a3a123c'
ENV['GITHUB_SECRET'] = '1234azer123azer1231209jeunsghezkndaz1234'
else
ENV['GITHUB_KEY'] = 'qsflkjkj685bg554456b'
ENV['GITHUB_SECRET'] = 'qslkfj7757kqfmlsdh675hlfsd587kjfdh687jsd'
end
See Is it possible to set ENV variables for rails development environment in my code? for more details on that.
I have 2 applications registered on github. One app_name-dev with key qsflk..., url http://localhost:3000 and callback url http://localhost:3000/auth/github/callback and one app_name with key d1234a....
Check that you have done that correctly. Maybe try to change localhost to 127.0.0.1.

For me it was Github's new stricter URI matching that was producing a 404 when trying to redirect to http://localhost:3000/auth/github/callback, I solved it by passing the redirect URI as a parameter with Omniauth.
Rails.application.config.middleware.use OmniAuth::Builder do
provider :github, ENV['GITHUB_KEY'], ENV['GITHUB_SECRET'],
:scope => 'user,public_repo',
:redirect_uri => ENV['GITHUB_REDIRECT']
end
If your on Linux/Mac you can add environment variables from the command line.
$ export GITHUB_REDIRECT=http://localhost:3000/auth/github/callback
Alternatively, you could use something like Foreman that will let you add a .env file which you can use to store your variables in.
Just remember to add the appropriate redirect URI to your production environment's variables, and you're good, to go.

Related

Rails 5.2 application secrets empty at Heroku

I deployed to Heroku with success but there is an issue with credentials.
I added RAILS_MASTER_KEY env variable at Heroku app CONFIG VARS section and copy-pasted the value from my app master.key file:
Then when I check its value from Heroku console, it is still nil:
Loading production environment (Rails 5.2.3)
irb(main):001:0> Rails.application.secrets.secret_key_base
=> nil
irb(main):002:0> Rails.application.secrets
=> {:secret_key_base=>nil, :secret_token=>nil}
irb(main):003:0>
But when I check it other way:
ENV['RAILS_MASTER_KEY']
=> "sdfghjklm.......1a0befa6139"
it is displayed correctly.
What am I missing?
I figured out myself, - I followed a Pluralsight tutorial on Rails API and it used the old way to get Rails secrets:
Rails.application.secrets.secret_key_base
Starting from Rails 5.2 there is no more secrets.yml file and the right way to get the env variables saved in credential.yml.encis as follows:
Rails.application.credentials.dig(:secret_key_base)
After updating the corresponding code, everything works as needed. Hope this helps.
Changing
SECRET = Rails.application.secrets.secret_key_base
to:
SECRET = ENV['SECRET_KEY_BASE'] || Rails.application.secrets.secret_key_base
worked for me.
ENV['SECRET_KEY_BASE'] worked in production environment while Rails.application.secrets.secret_key_base worked in development environment.

Does my Sinatra API application need a class declaration?

Someone developed an API application for me that works well. Unfortunately, it doesn't log anywhere and there are no logs at all. The app runs with the "rackup" command and sits behind an nginx web server. The Sinatra errors are not logged to the nginx logs.
The app.rb file looks something like this:
require './libs'
require 'sinatra'
require 'sinatra/namespace'
set :bind, '::1'
before do
content_type :json
headers 'Access-Control-Allow-Origin' => '*', 'Access-Control-Allow-Methods' => ['OPTIONS', 'GET', 'POST']
end
namespace '/api/v1' do
namespace '/getit/:thingtoget' do
helpers do
def myhelper1
<stuff>
end
def myhelper1
<stuff>
end
end
before do
myhelper1
myhelper2
end
get '/info' do
WidgetDomain::get_info(#va1, #var2).to_json
end
<more API paths here>
end
Now this is working fine. But now I want to introduce logging. So I looked at the Sinatra README and it said I could enable logging like so:
class MyApp < Sinatra::Base
configure :production, :development do
enable :logging
end
end
Do I put that above the namespace stuff? If I declare an app like that, does my namespace stuff need to be inside that app code somehow? I don't have a grasp of how this works at all.
It almost looks like it's trying to log in the nginx log, but here's what an error line looks like there:
2018/12/30 19:53:15 [error] 6615#0: *21522 connect() failed (111: Connection refused) while connecting to upstream, client: <someip>, server: api.example.com, request: "GET /api/v1/getit/thingtoget1/stuff/var1/var2/var3 HTTP/1.1", upstream: "http://[::1]:9292/api/v1/getit/thingtoget/stuff/var1/var2/var3", host: "api.example.com", referrer: "an HTML page from the nginx server"
It's almost like it's trying to connect back to the server to retrieve a message or something. But in case the logging has something to do with the way I've declared the server in the nginx configuration, here it is:
server {
listen 443;
listen [::]:443;
server_name api.myapp.com;
ssl on;
ssl_certificate /etc/nginx/ssl/myapp_com.pem;
ssl_certificate_key /etc/nginx/ssl/star_myapp_com.key;
location / {
proxy_pass http://localhost:9292;
}
}
Have a look at Sinatra's README in the Logging section but I tend to set up a logger outside of the Sinatra app in case other bits get bolted on or several apps are used together and I can use the same logger for all of them. Simplest way is a global variable (one of the few places they're acceptable, but it's not the only way) :
require 'mono_logger' # because it's thread safe
require 'pathname' # because paths aren't strings :)
log_path = Pathname(__dir__).join("logs/app.log")
$logger = MonoLogger.new(log_path)
$logger.level = MonoLogger::INFO
Then in a route or wherever:
get '/' do
$logger.info "here"
In my terminal:
$ cat logs/app.log
I, [2019-01-07T13:03:52.989415 #64378] INFO -- : here
As to configuration blocks, you don't need to worry about putting them within a class declaration unless you're using a modular app (see Modular vs. Classic Style in the README) and yours is in the classic style.
Configuration blocks aren't namespaced (Sinatra::Namespace handles things that take a route as an argument, like get and before) so follow convention and stick it near the top of the file.
Hope that helps.

Figaro - Rails Missing secret_key_base for development

I've just switched to using the Figaro gem v1.0.0 with Rails 4.1.6.
Since deleting my secrets.yml file I now get the error:
Unexpected error while processing request: Missing secret_key_base for 'development' environment, set this value in config/secrets.yml
Do i still need the secrets.yml file - isn't this the job of Figaro's application.yml file?
My application.yml file is like
development:
secret_key_base: 56....
Looking into the Railties gem at https://github.com/rails/rails/blob/master/railties/lib/rails/application.rb you can see the secrets method defined which includes a fallback for secret_key_base
def secrets #:nodoc:
#secrets ||= begin
secrets = ActiveSupport::OrderedOptions.new
yaml = config.paths["config/secrets"].first
if File.exist?(yaml)
require "erb"
all_secrets = YAML.load(ERB.new(IO.read(yaml)).result) || {}
env_secrets = all_secrets[Rails.env]
secrets.merge!(env_secrets.symbolize_keys) if env_secrets
end
# Fallback to config.secret_key_base if secrets.secret_key_base isn't set
secrets.secret_key_base ||= config.secret_key_base
secrets
end
end
In config/application.rb adding the following resolves the issue
config.secret_key_base = Figaro.env.secret_key_base
I have never used Figaro gem but try these, create the config/secret.yml file and inside write:
development:
secret_key_base: <%= ENV['secret_key_base'] %>
I was just informed that as of Rails 4.1.x, config/secrets.yml does need to be uploaded to heroku. Rails will no longer look directly at its ENV in order to find its secret_key_base.
So secrets.yml needs to come off of the .gitignore file, and your project would need to be recommited and re-pushed to heroku.
(secrets.yml would still get its values from heroku's ENV, which would still be loaded up via Figaro the same way as before - figaro heroku:set -e production. Use heroku config to get a nice quick look at your ENV variables to confirm they are there)

Sinatra - Error Handling

I'm trying to make my sinatra app show a custom error page when an error is raised on the server (e.g. an IOError or ArgumentError).
Currently I'm using AJAX to load the results into a certain #results div, but if and when an error arises on the server, I would like an error page to open up on a new page.
Currently, the IOError is shown on the server and a error is seen in the console (the server responded with a status of 500 (Internal Server Error)). Other than that, nothing happens.
I think that I have to play about with the Javascript (as well as the Sinatra::Base class) but I've spent the whole of yesterday and this morning not getting anywhere.
I would be very grateful for any help. I've created an oversimplified version of my app which I have shown below...
Sinatra_app.rb
require 'sinatra/base'
require9 'sinatra'
require 'slim'
# A helper module
module GVhelpers
def create_results(name)
# raise IOError, "There's a problem..."
return "<p>The Server Says 'Hey #{name}'</p>"
end
end
class GVapp < Sinatra::Base
helpers GVhelpers
set :root, File.dirname(__FILE__)
error do
#error = env['sinatra.error']
slim :"500", :locals => {:error => error}
end
get '/' do
slim :index
end
post '/form' do
name = params[:personName]
create_results(name)
end
end
GVapp.run!
index.slim (in views folder)
script src="/jquery.min.js"
script src="/Gvapp.js"
form#sayHey action="/form" method="post"
| Name:
input type="text" name="personName"
br
input type="submit"
#output
500.slim (in views folder)
h1 Oops! Something went Wonky!
p Apologies, there was an error with your request:
strong request.env['sinatra.error'].message
p If the error persists, please contact the administrator.
Gvapp.js (in public folder)
$(document).ready(function() {
$('#sayHey').submit(function(e) {
e.preventDefault();
$.ajax({
type: 'POST',
url: '/form',
data: $('#sayHey').serialize(),
success: function(response){
$('#output').html(response);
}
})
})
})
Sinatra swallows exceptions when run in the development environment by default and shows its debugging error page instead. So, to trigger your custom error handlers, you have to either run the application inside a Rack environment other than development (probably production), or preferably, tell Sinatra to not use its default error handlers in development mode.
Consider the following, standalone Sinatra application example:
require "sinatra"
#disable :show_exceptions
get "/" do
raise RuntimeError.new("boom")
end
error RuntimeError do
"A RuntimeError occured"
end
If you run this application using the default development environment like this:
$ ruby foo.rb
Then you will get Sinatra’s default error page. If you uncomment the disable line in the example, the error handler will be triggered instead, displaying a page containing "A RuntimeError occured". Alternatively, you can, as explained, run the application in an environment other than development as only that one pre-sets the show_exception setting. You can do that by setting the RACK_ENV environment variable:
$ RACK_ENV=production ruby foo.rb
For development purposes, setting RACK_ENV to production is not the correct way of course. Use disable :show_exceptions instead. You can use a configure block as outlined in the Sinatra README to conditionally disable the setting for the development environment.
configure :development do
disable :show_exceptions
end
That behaviour is documented in Sinatra’s documentation on configuration, along with several other useful settings.

Use proxy IP with a ruby script

I am trying to run a ruby script from my computer and I would like to have the script use a proxy IP address / server that I have setup, as opposed to the default IP address associated with my local machine.
I have been able to get my web browsers to use this proxy IP address by making changes inside network settings. But When I run the ruby script from textmate, it doesn't seem to use the proxy IP address I have put into my network settings. Instead it defaults back to the base ip address of my local machine.
Is there anything I can do in textmate or in the script itself to specify a proxy IP address it should route through?
My script looks like the following:
require "open-uri"
url = "some-url"
pattern = "<img"
page = open(url).read
tags = page.scan(pattern)
puts "The site #{url} has #{tags.length} img tags"
Thanks for your help!
Use :proxy option to let open-uri know your proxy server:
page = open(url, :proxy => "http://#{proxy_host}:#{proxy_port}/").read
You can also set environment variable http_proxy instead. If you do so, give :proxy => true for option.
page = open(url, :proxy => true).read
[ADDED]
If you want to use proxy with basic authentication, you can give :proxy_http_basic_authentication option instead of :proxy as follows:
:proxy_http_basic_authentication => ["http://#{proxy_host}:#{proxy_port}/", login, password]
Note that :proxy_http_basic_authentication can be used in ruby 1.9.2 or later.
I recommend using mechanize, and css instead of regex:
require "mechanize"
url = "http://www.google.com/"
#agent = Mechanize.new{|a| a.set_proxy 'localhost', 8888}
page = #agent.get url
tags = page.search('img')
puts "The site #{url} has #{tags.length} img tags"

Resources