Why I'm getting undefined method `cookies'? - ruby-on-rails

I'm trying to setup Authlogic with single_access_token for my rails backend app (I'm using rails-api gem).
I'm following this example: http://blog.centresource.com/2013/06/04/using-ember-auth-with-rails-3-and-authlogic/
So far, I'm able to create users, but when I try to login it fails on user_session.save:
NoMethodError in Api::V1::UserSessionsController#create
undefined method `cookies' for #<Api::V1::UserSessionsController:0x00000004528cb8>
According to similar questions I've found here, I have to configure Authlogic as:
acts_as_authentic do |c|
c.login_field = :email
c.maintain_sessions = false
end
on my User model. However, it keeps failing. I'm assuming when UserSession is saved, Authlogic tries to update the magic fields on User, but I have no idea why is still trying to use cookies.

The tutorial assumes a regular rails app, but you're using rails-api. By default controllers in rails-api don't include the middleware that handles cookies. If you need cookies then you need to add that middleware:
config.middleware.use ActionDispatch::Cookies
And then include ActionController::Cookies in your controller. There's more info on what's included by default in the rails-api README

Rails-api does have additional steps to accept cookies
add config.middleware.use ActionDispatch::Cookies to config/application.rb
add at the top under class include ActionController::Cookies in your expected controller
Restart the application

Related

Not able to create session with an object

I'm trying to implement my first authlogic-based app in ruby on rails. I need to sign user using a custom oauth2 flow, at the end of the process, I want to tell authlogic which user I want him to authenticate. Without providing a login nor password, just directly by passing a user object.
I've found in the README that I can do that using UserSession.create(user, true) but putting this at the end of my OAuth callback step is not persisting my user. There is no error nor exception, everything seems to be fine but UserSession.find returns nil (even in the next line after the UserSession.create). I'm on rails 5.1.6 and authlogic 4.0.1.
User model
class User < ApplicationRecord
acts_as_authentic
end
UserSession model
class UserSession < Authlogic::Session::Base
end
Thanks in advance for any clues about what I did wrong.
This is what I found out, from Authlogic::Session::Base
module Authlogic
module Session # :nodoc:
# This is the most important class in Authlogic. You will inherit this class
# for your own eg. `UserSession`.
#
# Code is organized topically. Each topic is represented by a module. So, to
# learn about password-based authentication, read the `Password` module.
#
# It is common for methods (.initialize and #credentials=, for example) to
# be implemented in multiple mixins. Those methods will call `super`, so the
# order of `include`s here is important.
#
# Also, to fully understand such a method (like #credentials=) you will need
# to mentally combine all of its definitions. This is perhaps the primary
# disadvantage of topical organization using modules.
as I read from their instructions, they do never say that you can authenticate user without email and password, but that you can create a session with the User object
# skip authentication and log the user in directly, the true means "remember me"
UserSession.create(my_user_object, true)
I would read more about the Session.rb
https://github.com/binarylogic/authlogic/blob/master/lib/authlogic/session/session.rb
sorry if I can not give you more help
PS you can also debug this gem by setting a binding.pry in the gem files

Custom callback for RailsAdmin::MainController

I have an role column in my User model and I want to prevent someone from accessing the rails_admin routes if they don't have an admin flag. Since the RailsAdmin::MainController doesn't inherit from ApplicationController I'm not sure how I can insert this check before the view loads.
I'm not keen on creating a new Admin model as per the devise docs. I would like to use the same user account.
Does anyone have any suggestions? =)
You can define from which controller your rails admin will inherit by defining it in the config/initializers/rails_admin.rb file like this:
RailsAdmin.config do |config|
config.parent_controller = '::ApplicationController'
end
And also i recommend using a gem to handle authorization, cancancan or pundit will handle nicely your use case.

Issues with loading custom Omniauth provider in Devise

I'm having issues with setting up a custom OmniAuth strategy to use with Devise. Im using the following gem here but im unsure on how to properly load this file and use it.
https://github.com/aereal/omniauth-xauth
Based on the README, i created a subclass specific for my provider, i didn't know really where to place this file, so i placed it here lib/strategies/myauth.rb based on this article. The file looks something like this. Removing the provider specific code.
module OmniAuth
module Strategies
class Myauth < OmniAuth::Strategies::XAuth
...
end
end
end
Based on this article i added the following code to my config/initializers/omniauth.rb
module OmniAuth
module Strategies
module XAuth
autoload :myauth, Rails.root.join('lib', 'strategies', 'myauth')
end
end
end
I did not add the following code, since i've read that by adding the config.omniauth :myauth in my config/initializers/devise.rb will take care of loading it. ??
Rails.application.config.middleware.use OmniAuth::Builder do
provider :myauth
end
I also added the following to my user.rb
devise :database_authenticatable, :omniauthable, :omniauth_providers => [:myauth]
I've also updated my config/initializers/devise.rb
config.omniauth :myauth, 'CKEY', 'CSEC', strategy_class => OmniAuth::Strategies::XAuth::Myauth
So when i try and run rails s i get the following error output.
`load_missing_constant': Unable to autoload constant Myauth, expected ...../PROJECT/lib/strategies/myauth.rb to define it (LoadError)
Any ideas on what im missing? Thanks for your time
You don't need config/initializers/omniauth.rb file as you already have myauth.rb.
Your strategy class should contain the following:
config.omniauth :myauth, 'CKEY', 'CSEC', strategy_class => OmniAuth::Strategies::Myauth
Rest should work as long as the content of Myauth class is right.
Please let me know if i have misunderstood your question and answered incorrectly.

How to protect rspec_api_documentation apitome route without a controller

I have a set of API documentation pages that I want to password protect using devise. The docs are generated using rspec_api_documentation. The gem uses rspec to execute the API methods and create html or json doc files. I'm generating json and using another gem, apitome, as a viewer.
This is all working beautifully and my api docs can be found at /api/docs, but I can't figure out how to require authentication to view the docs.
The docs are viewed through apitome so it using rails. There isn't a route in routes.rb, but the apitom initializer mounts the docs.
From apitom initializer:
# This determines where the Apitome routes will be mounted. Changing this to "/api/documentation" for instance would
# allow you to browse to http://localhost:3000/api/documentation to see your api documentation. Set to nil and mount
# it yourself if you need to.
config.mount_at = "/api/docs"
https://github.com/zipmark/rspec_api_documentation
https://github.com/modeset/apitome
I found this How-to that is supposed to make every page on the site require authenication, but I'm still able to hit the docs url without signing in.
#https://github.com/plataformatec/devise/wiki/How-To:-Require-authentication-for-all-pages
Thanks for any help.
You can take control of Apitome controller and request auhentication.
configure apitome to not mount itself by setting mount_at to nil
write your controller ApidocsController extending Apitome::DocsController
add before_filter :authenticate_user! in your controller
add a route to your controller: get '/api/docs', to: 'apidocs#index'
Controller implementatin would go like this:
class ApidocsController < Apitome::DocsController
before_filter :authenticate_user!
end
If you have Devise already configured (for example if you already use ActiveAdmin) you can share the same authenticated session.
You have to disable the default mounting of Apitome:
# config/initializers/apitome.rb
Apitome.setup do |config|
config.mount_at = nil
# ...
end
Since this will break links in Apitome, you have to add to your application.rb:
# config/application.rb
# ...
class Application < Rails::Application
config.after_initialize do
Apitome.configuration.mount_at = '/docs'
end
# ...
end
Then force mount of the Apitome engine under Devise authenticated session:
# config/routes.rb
Rails.application.routes.draw do
# ...
authenticated :admin_user do
mount Apitome::Engine => '/docs'
end
# root_to ...
end
Now /docs is accessible only for already authenticated users.
PS: replace :admin_user (default for Active Admin) to :user or any other model name where Devise is configured.
I am using the cut down rails api, so did not have any views or devise and so no simple way to implement password protection. Accordingly I went for the following solution.
Apitome.setup do |config|
config.mount_at = nil
# ...
end
and in the routes.rb file:
mount Apitome::Engine => '/api/docs' unless Rails.env.production?
Finally, I just did a pdf of the api/docs page, and then sent the pdf to anyone what had a right to see the documentation. Obviously not suitable for a large user base, but works fine for a small one, e.g. within a company's IT group.
If anyone is using Raddocs, add mounted route inside authentication block as below:
authenticate :user do
mount Raddocs::App => "/docs"
end

override "/auth/identity"-page of omniauth identity

I'm using omniauth without devise for authentication, as I like it's simplicity. In addition to omniauth-facebook I use omniauth-identity to offer email/pw-authentication.
The railscast on omniauth-identity describes how to setup a customized registration and login page. But the default routes supplied by identity (/auth/identity and /auth/identity/register) are still accessible.
I would like to have these under my control, as I want only want to let invited users register. Is there any way to override those routes supplied by a rack middleware?
Trying to just
match "/auth/identity", to: "somewhere#else"
doesn't do the trick!
Is there maybe a configuration to turn these default routes off? The documentation isn't giving any details on this...
Unfortunately I'm fairly new to Rack, so I don't have enough insight yet, to solve this issue on my own!
I'd be glad, if someone could point me in the right direction!
An OmniAuth strategy object has a method request_phase which generates a html form and shows it to user. For "omniauth-identity" strategy this would be the form you see at /auth/identity url.
You can override the request_phase method and replace the form generator with, for example, a redirect to your custom login page (assuming you have it available at /login url). Place the following along with your omniauth initialization code:
module OmniAuth
module Strategies
class Identity
def request_phase
redirect '/login'
end
end
end
end
# Your OmniAuth::Builder configuration goes here...
In addition to 1gors and iains answer:
"/auth/identity/register" is served with GET as well, to override, I had to:
class OmniAuth::Strategies::Identity
alias :original_other_phase :other_phase
def other_phase
if on_registration_path? && request.get?
redirect '/sign_up'
else
original_other_phase
end
end
end
You can set method in omniauth.rb
:on_login => SessionsController.action(:new)
for example:
Rails.application.config.middleware.use OmniAuth::Builder do
provider :identity,
:fields => [:nickname],
:on_login => SessionsController.action(:new),
:on_registration => UsersController.action(:new),
:on_failed_registration => SessionsController.action(:registration_failure)
end

Resources