session[:id] variable not being picked up within another route from sinatra - ruby

I am following this tutorial here on setting up a user login https://learn.co/lessons/sinatra-user-auth
It says that in order to save a session[:id] in my route I would do something like this:
post '/login' do
#user = User.get_id(params['email'],params['password'])
session[:id] = #user # equals a numeric value of the matching user
redirect '/home'
end
however, when i get to my /home route I am no longer able to access the session[:id] that was set in my /login route, it returns nil
# this doesnt return the session id
# consequently I cant lookup my user records
get '/home' do
#user = User.object(session[:id]) # looks up user object with numeric value
erb :home
end
I have tried enabling sessions in my config controller, that didnt work either
module Controllers
class ApplicationController < Sinatra::Base
# . . . .
configure :production, :development do
enable :sessions, :logging
end
end
end
how do I make my app persist the session[:id] between routes?

Have you tried enable :sessions after you require your sinatra gem in your sinatra app? Not in your controller

Related

How do I set a current_user in Rack middleware for GraphQL

I'm using GraphQLPlayground configured in my config.ru
map "/graphql-playground" do
use GraphqlPlaygroundAuthentication
use GraphQLPlayground, endpoint: "/graphql"
end
end
And I want to authorize my requests via GraphqlPlaygroundAuthentication since Rack does not send cookies with the request.
In my graphql_controller.rb I have this:
def execute
variables = prepare_variables(params[:variables])
query = params[:query]
operation_name = params[:operationName]
context = {
current_actor: current_user
}
# more code here
How do I set current_user inside of GraphqlPlaygroundAuthentication.rb?
I have tried to set cookies with Rack::Utils.set_cookie_header! but even though I see the cookies inside Application tab in my browser, my current_user inside request is nil.
I have no idea how to set the current_user to be available inside the controller and then my playground requests are unauthorized.
Reason why Playground is mounted inside config.ru and not routes.rb: CSP configuration of my project. I cannot change that.
You need to define current_user method in your controllers/application_controller.rb.
class ApplicationController < ActionController::API
def current_user
# If test situation when user is logged in
User.first
# If test situation when user is not logged in
# nil
end
end

Facebook Graph API for websites using Ruby Koala gem in Sinatra

I want to implement Facebook login for web apps. All I need is the basic public information of a user for the account creation steps.
This is what I have done:
Created a basic Facebook app with nearly no custom permissions.
Used the APP_ID and APP_SECRET in Koala to get access_token.
Everything worked perfectly, I am able to login/logout.
Just that the only information I am able to get back when I do: graph.get_object('me') is the logged in user's name and an id (It doesn't look like the default Facebook id).
Surprised whether something changed in the new API, I tested the gem in the console using the access_token from graph explorer (where all permissions are enabled by default). And I get all data using the same method call.
When I review what all the app gets while signing up; I see that the user's basic information, profile pic and other public data will be accessible to the app.
Any idea why this is so? It seems I am missing something obvious. The code is available in Github. But this is pretty much everything to it:
require 'bundler'
Bundler.require :default
Dotenv.load '.env'
require_relative './app/constants.rb'
module Banana
class App < Sinatra::Base
use Rack::Session::Cookie, secret: COOKIE_SECRET
set :public_folder, File.dirname(__FILE__) + '/bower_components'
get '/' do
if logged_in?
haml :welcome_in, layout: :layout
else
haml :log_in, layout: :layout
end
end
get '/log_out' do
session['oauth'] = nil
session['access_token'] = nil
redirect '/'
end
get '/log_in' do
session['oauth'] = Koala::Facebook::OAuth.new(APP_ID, APP_SECRET, "#{request.base_url}/call_back")
redirect session['oauth'].url_for_oauth_code()
end
get '/call_back' do
begin
session['access_token'] = session['oauth'].get_access_token(params[:code])
rescue
redirect '/?error=user_denied'
end
redirect '/'
end
get '/test' do
if logged_in?
p graph.get_object("rakeshbs")
"e"
else
redirect '/'
end
end
def logged_in?
!session['access_token'].nil?
end
def toggle_access
logged_in? ? '/log_out' : '/log_in'
end
def graph
#graph ||= Koala::Facebook::API.new(session['access_token'])
end
def errored?
!params["error"].nil?
end
def user
p graph.get_connections(:me, :photos) # This is just nil
#user ||= OpenStruct.new(
name: graph.get_object("me")["name"], # All I get here is just a hash with the name and an id!
photo: 'http://semantic-ui.com/images/avatar/small/elliot.jpg'
)
end
end
end
You should add fields parameter.
Something like this:
graph.get_object('me', { fields: 'id,first_name,last_name,gender,birthday,photos,email' })

Rails access request in routes.rb for dynamic routes

Our websites should allow to show different contents related to the given url .. something like a multisite in wordpress where we have one installation and serve the content according to the url.
as it is necessary to have the routes in the correct language I want to use a "dynamic route" approach to serve the right content. My problem is now that I dont find a way how to serve the proper routes in routes.rb if they are dynamic.
How can I "access" or "pass" the request object into any method inside the routes.rb file
f.e. like this
routes.rb
Frontend::Application.routes.draw do
DynamicRouter.load request
end
app/models/dynamic_router.rb
class DynamicRouter
def self.load request
current_site = Site.find_by_host(request.host)
Frontend::Application.routes.draw do
current_site.routes do |route|
get "#{route.match}", to: "#{route.to}"
end
end
end
end
this doesnt work because request is undefined in routes.rb
To answer your question: How can I "access" or "pass" the request object into any method inside the routes.rb file Obtain it as ENV object from rack middleware.See code below
# lib/dynamicrouterrequest.rb
require 'rack'
class DynamicRouterRequest
def initialize(app)
#app = app
end
def call(env)
request=Rack::Request.new(env)
ENV["OBJ_REQUEST"]=request.inspect.to_s
#app.call(env)
end
end
Grab it again in routes
# routes.rb
Frontend::Application.routes.draw do
request=ENV["OBJ_REQUEST"]
DynamicRouter.load request
end
A possible soluction is to create the default rules on routes.rb and add a rack middleware that can transform a path according to the domain
# routes.rb
get '/category/:id', :to => 'categories#show'
In the middleware you can transform a path like 'categoria/:id' to '/category/:id' if the domain matches '.es', before the application hits the router layer.
More on rack middleware: http://guides.rubyonrails.org/rails_on_rack.html

How do I do a really simple Sinatra LDAP authentication?

I looked at the Sinatra docs and they only seem to reference HTTP authentication. I'm looking for a really simple way to control access to routes based on a user being authorised/authenticated via an LDAP server.
I've already built a class that does the LDAP bit and returns an LDAP object if the user has successfully authenticated and nil if they haven't:
>>DirectoryUser.authenticate('user', 'password')
#<DirectoryUser:0x007ffb589a2328>
I can use this to determine if they've successfully authenticated or not.
As a next step I want to splice this into a simple Sinatra app that provides a form to collect the LDAP user and password:
require 'directoryUser'
require 'sinatra'
enable :sessions
get '/form' do
username = params[:username]
password = params[:password]
haml :form
end
Then I want to only allow routes if the 'DirectoryUser' object exists:
get '/protected' do # Only if DirectoryUser object exists
"This route is protected"
end
get '/unprotected' do
"This route is unprotected"
end
I've spent hours trying to find an answer to this but so far and can't seem to find anything that works for me.
I'd probably go with something like this:
require 'directoryUser'
require 'sinatra'
enable :sessions
helpers do
def authorize!
redirect(to('/login')) unless session[:user_id]
end
end
get '/login' do
haml :login # with the login form
end
post '/login' do
user = DirectoryUser.authenticate(params[:username], params[:password])
if user
session[:user_id] = user.id
# Or: session[:logged_in] = true, depending on your needs.
redirect to('/protected')
else
redirect to('/login')
end
end
get '/protected' do
authorize!
'This route is protected'
end
get '/unprotected' do
'This route is unprotected'
end

How can you set up scoped redirects for Sinatra apps

I have a series of sinatra applications that are set up such that each is responsible for one thing.
Let's say I have two apps like this:
class Foo < Sinatra::Base
get '/' do
'FOO!'
end
end
class Zoo < Sinatra::Base
get '/' do
'ZOO!'
end
get '/zoom' do
# do things
redirect '/'
end
end
Now let's say I have my config.ru as such:
require './application'
run Rack::URLMap.new('/' => Foo.new, '/zoo' => Zoo.new)
The problem I'm running into is when I try to do the redirect in the zoom action I get sent off to the index action of Foo instead of Zoo. Is there a clean way to do this such that my applications don't need to know how the routes are set up for the app?
You can use configurable redirects. See http://www.sinatrarb.com/2011/03/03/sinatra-1.2.0.html#configurable_redirects.
E.g.
class Zoo < Sinatra::Base
get '/' do
'ZOO!'
end
get '/zoom' do
# do things
redirect to('/')
end
end
Or alternatively, as mentioned in the link above, skip the to() call by enabling prefixed redirects in the Zoo app:
class Zoo < Sinatra::Base
enable :prefixed_redirects
...

Resources