Devise user authentication in grape - ruby-on-rails

I have a rails application that contains all front-end part , administrative and register/login/logout (Devise).
I also have a part with more dynamic maps that is written in javascript React. It runs on a controller / view separately in the same application.
I created an api using Grape to expose the data to React.
My question is how to know that the user is logged in without the use of tokens.
Which way ? I can use cookies and session stored in the browser? How would?
I can get the user id by:
user_id = env['rack.session']['warden.user.user.key'].first.first
That would be fine?
User.find(user_id)
It's safe?

One of my application I have use devise authentication like below:
api.rb
#require 'grape'
module Base
class API < Grape::API
prefix 'api'
version 'v1', :using => :header, :vendor => 'vendor'
format :json
helpers do
def current_user
user = User.where(authentication_token: params[:auth_token], is_approved: true).first
if user
#current_user = user
else
false
end
end
def authenticate!
error!('401 Unauthorized', 401) unless current_user
end
end
# load the rest of the API
mount V1::Registration
mount V1::Sessions
end
end
sessions.rb
module V1
class Sessions < Grape::API
version 'v1', using: :path
format :json
prefix :api
resource :sessions do
##<$ User Sign In API $>##
desc 'Authenticate user and return user object / access token'
params do
requires :email, type: String, desc: 'User email'
requires :password, type: String, desc: 'User Password'
end
post do
email = params[:email]
password = params[:password]
if email.nil? or password.nil?
error!({error_code: 404, error_message: 'Invalid Email or Password.'}, 401)
return
end
user = User.where(email: email.downcase).first
if user.nil?
error!({error_code: 404, error_message: 'Invalid Email or Password.'}, 401)
return
end
if !user.valid_password?(password)
error!({error_code: 404, error_message: 'Invalid Email or Password.'}, 401)
return
else
user.ensure_authentication_token
user.save
{status: 'ok', auth_token: user.authentication_token}
end
end
desc 'Destroy the access token'
params do
requires :auth_token, type: String, desc: 'User Access Token'
end
delete ':auth_token' do
auth_token = params[:auth_token]
user = User.where(authentication_token: auth_token).first
if user.nil?
error!({error_code: 404, error_message: 'Invalid access token.'}, 401)
return
else
user.reset_authentication_token
{status: 'ok'}
end
end
end
end
end

Related

Problem with create authenticate api using grape in ruby on rails

I want to do authenticate API using grape. For auth I used Devise gem. I try include devise::sessioncontroller into my grape api file but it's caput.
class SignIn < BaseAPI
resource :sign_in do
desc 'Sign in page'
params do
requires :username, type: String
end
post do
User.authenticate(params)
end
end
end
Try the following code. You should be able to authenticate. There are a few extra things you need to set up. Follow this document for more details.
resource :sign_in do
desc "Authenticate user"
params do
requires :login, type: String
requires :password, type: String
end
post :login do
user = User.find_by_email(params[:login].downcase)
if user && user.authenticate(params[:password])
token = TokenGenerator.create(user_id: user.id)
{token: token.access_token}
else
error!('Unauthorized.', 401)
end
end
end

signIn with Devise from an API

I have a problem with the user authentication. I exposed a user API and the json output is like this:
[
{
id: 1,
email: "khelif.ghassen#gmail.com",
nom: "Ghassen",
prenom: "Khelif",
created_at: "2017-11-05T03:18:19.640Z",
updated_at: "2017-11-05T03:18:19.644Z"
}
]
I can't see the crypted password
for this moment I'm just showing up all users (I have just on user for this moment) and this is my class to return this JSON
`
module TESTAPP
module V1
class Users < Grape::API
version 'v1', using: :path
format :json
prefix :api
resource :users do
desc "Return list of users"
get do
User.all
end
desc "Return an objet"
params do
requires :id, type: Integer, desc: "User id"
end
route_param :id do
get do
User.find(params[:id])
end
end
end
end
end
end

Ruby on rails, facebook login get friends and AccessToken

I have created an app with a facebook login using :
gem "koala"
gem 'omniauth'
gem 'omniauth-facebook', '1.4.0'
gem 'fb_graph2'
I want to get access to user friends who use the app too.
But I don't know how to do that and how to have the 'access token' because I don't understand what is the access token ...
Right now, here is the code that I have.
models/ user.rb
class User
include Mongoid::Document
include Mongoid::Timestamps
field :provider, type: String
field :uid, type: String
field :name, type: String
field :picture, type: String
field :auth_token, type: String
has_many :parties
has_many :invitations, :class_name => 'Invite', :foreign_key => 'recipient_id'
has_many :sent_invites, :class_name => 'Invite', :foreign_key => 'sender_id'
has_many :friends
# TODO: Ajouter les amitiƩs
# TODO: Ajouter les recherches d'amis (livereload)
def self.create_with_omniauth(auth)
create! do |user|
user.provider = auth['provider']
user.uid = auth['uid']
user.auth_token = auth['credentials']['token']
if auth['info']
user.name = auth['info']['name'] || ""
user.picture = auth['info']['image'] || ""
end
end
end
def large_image
return "http://graph.facebook.com/#{self.uid}/picture?type=large"
end
def normal_image
return "http://graph.facebook.com/#{self.uid}/picture?type=normal"
end
end
controllers / sessions_controller.rb
class SessionsController < ApplicationController
def create
auth = request.env["omniauth.auth"]
user = User.where(:provider => auth['provider'],
:uid => auth['uid']).first || User.create_with_omniauth(auth)
session[:user_id] = user.id
redirect_to root_url, :notice => "Signed in!"
end
def destroy
reset_session
redirect_to root_url, :notice => 'Signed out!'
end
def new
redirect_to '/auth/facebook'
end
def failure
redirect_to root_url, :alert => "Authentication error: #{params[:message].humanize}"
end
end
initializer / omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, '<public_key>', '<private_key>'
end
And my friends controller :
class FriendsController < ApplicationController
def index
if params[:code]
session[:access_token] = session[:oauth].get_access_token(params[:code])
end
# auth established, now do a graph call:
#api = Koala::Facebook::API.new(session[:access_token])
#user_profile = #api.get_object("me")
#friends = #api.get_connections(#user_profile['id'], "friends")
end
end
It don't work, I have this error :
type: OAuthException, code: 2500, message: An active access token must be used to query information about the current user., x-fb-trace-id: BeOG6OGemO9 [HTTP 400]
I imagine that it's because my code is not correct, so I hope someone should help me improve my code and get access to user friends !
The token that you saved in users.auth_token field is what you need. So when initializing a new Koala instance pass users auth_token - #api = Koala::Facebook::API.new(current_user.auth_token) and then try to get friends list, like you do currently.
Regarding what access token is you can read about it here (in Facebook context) https://developers.facebook.com/docs/facebook-login/access-tokens

Rolling a token auth mechanisim on top of devise [Rails 4]

Aloha,
After discovering Devise' token_authenticatable has been depreciated, I'm now attempting to roll my own solution, however I think I'm having an issue with devise' sign_in method:
spec:
context "with an admin user" do
before(:each) { #user = FactoryGirl.create(:user, account_type: 'admin') }
it "should respond with a 200 status" do
post :verify, "token"=> #user.authentication_token
response.status.should eq(200)
end
end
error:
1) UsersController#verify with an admin user should respond with a 200 status
Failure/Error: post :verify, "token"=> #user.authentication_token
NoMethodError:
undefined method `user' for nil:NilClass
# ./app/controllers/application_controller.rb:24:in `authenticate_user_from_token!'
# ./spec/controllers/users_controller_spec.rb:39:in `block (4 levels) in <top (required)>'
application_controller.rb:
class ApplicationController < ActionController::Base
# If there's a token present we're using the api authentication
# mechanism, else we fall back to devise auth
before_filter :authenticate_user_from_token!, :authenticate_user!
# Setup an AccessDenied error
class AccessDenied < StandardError; end
# setup a handler
rescue_from AccessDenied, :with => :access_denied
private
# API requests should be made to the resource path
# with the requesters token as params.
#
# This method extracts the params, checks if they are
# valid and then signs the user in using devise' sign_in method
def authenticate_user_from_token!
user = User.find_by_authentication_token params[:token]
if !user.nil? && user.admin?
# store: false ensures we'll need a token for every api request
sign_in user, store: false # this is the line the spec complains about
else
raise ApplicationController::AccessDenied
end
end
def access_denied
render :file => "public/401", :status => :unauthorized
end
end
users_controller.rb
class UsersController < ApplicationController
[snip]
# We use this 'verify' method to provide an endpoint
# for clients to poll for token verification
# If the before filter rejects the user/token
# they recieve a 401, else we respond with a 200
# and the user params for verification on the remote app
def verify
user = User.find_by_authentication_token params[:token]
render json: user
end
end
I don't know where the 'user' method the error mentions is being called, nor what the object it's being called on is.
I've found Authy's devise module very easy to use/modify for token based authentication, rather than rolling my own from scratch.

Rails authentication with LDAP and local database

I am trying to rewrite an older app that was created with PHP/MySQL.
The authentication system used has a users table in the database that stores username, email etc... but NOT passwords.
Whenever the user logs in it first checks the database to see if the user exists if not then returns a login error. If the user exists in the local database then it tries to bind to the active directory using the username/password combination entered by the user and creates a session if successful.
What is the best way to accomplish this using Rails?
Ruby's Net::LDAP library is pretty good.
Here's a simplified version of what I've been using for years:
# sessions_controller.rb
def create
user = User.find_by_login(params[:login])
if user && Ldap.authenticate(params[:login], params[:password])
self.current_user = user
Rails.logger.info "Logged in #{user.name}"
flash[:notice] = "Successfully Logged In!"
redirect_back_or_default root_url
else
flash[:alert] = "Invalid User credentials"
render :new
end
end
# lib/ldap.rb
# Ldap.authenticate('user','password')
# Returns true if validated
# Returns false if invalidated
# Returns nil if LDAP unavailable
require 'net/ldap'
class Ldap
def self.config
# this is actually loaded from a yaml config file
{
:domain => 'YOURDOMAIN',
:host => '10.10.10.100'
}
end
def self.authenticate(login, password)
conn = Net::LDAP.new(
:host => config[:host],
:port => 636,
:base => "dc=#{config[:domain]}, dc=local",
:encryption => :simple_tls,
:auth => {
:username => "#{login}##{config[:domain]}.local",
:password => password,
:method => :simple
}
)
Timeout::timeout(15) do
return conn.bind ? true : false
end
rescue Net::LDAP::LdapError => e
notify_ldap_admin(config[:host],'Error',e)
nil
rescue Timeout::Error => e
notify_ldap_admin(config[:host],'Timeout',e)
nil
end
def self.notify_ldap_admin(host,error_type,error)
msg = "LDAP #{error_type} on #{host}"
RAILS_DEFAULT_LOGGER.debug(msg)
DeveloperMailer.deliver_ldap_failure_msg(msg,error)
end
end
Check out the devise and devise_ldap_authenticatable libraries.

Resources