I want a password site wide just like Rack's Basic AUTH
/config.ru
use Rack::Auth::Basic, "Restricted Area" do |username, password|
[username, password] == ['admin', 'admin']
end
run Rails.application
But I don't want it to block paths /API and /mailgun/incoming_email with password access. Can I accomplish this in Rack? Or should I implement a scope within the routes.rb that almost all resources are behind a Rack (enter once) password?
For the record I am using Devise within the site... that's separate. I need a sitewide password before it.
[Revised Question]
Specific Routes
I would like to password protect only the root path / and /visitors with the Rack like password. I've seen something used in a Rails routes.rb file before with a lambda condition requiring the password. I'm not having luck finding that information at the moment.
My website already redirects unauthenticated Devise users to /users/sign_in. So I only needed to password protect /, /users/sign_in, and /users/sign_up. This is how I did it.
config.ru
class RootSiteAuth < Rack::Auth::Basic
def call(env)
request = Rack::Request.new(env)
if ['/', '/users/sign_in', '/users/sign_up'].include? request.path
super
else
#app.call(env)
end
end
end
use RootSiteAuth, "Restricted Area" do |username, password|
[username, password] == ['admin', 'admin']
end
run Rails.application
And it works. Every controller that has before_filter :authenticate_user! redirects to the Rack password page. After authentication we're good to go. Anything without the filter permits outside access as planned. ^_^
Related
I have a rails(4.2.0) application that uses Facebook login functionality. The main gems are devise(3.4.0) and omniauth-facebook(2.0.0). I have registered the application on Facebook and have been using its test app for development. The Facebook login functionality works in the development env.
When trying to use the facebook login feature on the production server, I get error as "Given URL is not allowed by the Application configuration: One or more of the given URLs is not allowed by the App's settings. It must match the Website URL or Canvas URL, or the domain must be a subdomain of one of the App's domains."
The details for settings for test app being used in the dev env are as -
Settings:
Basic:
App Domains: 'localhost'
Website:
Site URL: 'http://localhost:3000'
Advanced:
OAuth Settings:
Embedded browser OAuth Login: Yes
Valid OAuth redirect URIs: "http://localhost:3000/users/auth/facebook/callback"
The details for settings for registered app being used in the production env are as -
Settings:
Basic:
App Domains: 'www.mysite.co'
Website:
Site URL: 'http://www.mysite.co'
Advanced:
OAuth Settings:
Embedded browser OAuth Login: Yes
Valid OAuth redirect URIs: "http://www.mysite.co/users/auth/facebook/callback"
I have specified the following in my secrets.yml
development:
secret_key_base: some_secret_key
facebook:
app_id: test_app_id
app_secret: test_app_secret
production:
secret_key_base: some_secret_key
facebook:
app_id: registered_app_id
app_secret: registered_app_secret
And have been using the creds from secrets.yml in the devise initialiser as
# ==> OmniAuth
# Add a new OmniAuth provider. Check the wiki for more information on setting
# up on your models and hooks.
# config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
require 'omniauth-facebook'
config.omniauth :facebook, Rails.application.secrets.facebook['app_id'], Rails.application.secrets.facebook['app_secret'], scope: ['user_photos', 'email', 'public_profile']
The actual domain name(blackened) has no typos anywhere and is same wherever it is used.
Contains of routes.rb related to omniauth are as
cat config/routes.rb
Rails.application.routes.draw do
root 'home#index'
devise_for :users, controllers: { omniauth_callbacks: "users/omniauth_callbacks" }
# routes related to other controllers
end
The routes are as below
bundle exec rake routes | grep user
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
user_omniauth_authorize GET|POST /users/auth/:provider(.:format) users/omniauth_callbacks#passthru {:provider=>/facebook/}
user_omniauth_callback GET|POST /users/auth/:action/callback(.:format) users/omniauth_callbacks#:action
The only code related to omniauth in the entire app is as
$ cat app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
def facebook
#You need to implement the method below in your model (e.g. app/models/user.rb)
#user = User.from_omniauth(request.env["omniauth.auth"])
if #user.persisted?
sign_in_and_redirect #user, event: :authentication #this will throw if #user is not activated
set_flash_message(:notice, :success, kind: "Facebook") if is_navigational_format?
else
session["devise.facebook_data"] = request.env["omniauth.auth"]
redirect_to new_user_registration_url
end
end
end
Upon further digging the problem, it was observed that the error didnt occur when 'www.example.com' was specified in the url and hence, the callback worked. When 'example.com' was specified in the address bar and facebook login tried, the login crashed with the above error.
So, I fixed the above issue by making some changes to the settings in for the facebook app. I donno if this is the right approach but it worked out. Just making the change as in point 2 didnt solve the problem.
Changes are:
1) Specified the 'App Domains' with 'example.com' and 'www.example.com'
2) Enabled 'Client OAuth Login' to 'Yes'
3) Specified 'Valid OAuth redirect URIs' with 'http://example.com/users/auth/facebook/callback' and 'http://www.example.com/users/auth/facebook/callback'
Ok, so I assume that you have a web app NOT running on Facebook that simply uses the Facebook OAuth flow for login functionality, correct? If so, you must enable "Client OAuth Login" in your application settings for the production environment. If you don't, then the web OAuth flow will not work. See this article: https://developers.facebook.com/docs/facebook-login/security
I have two classes of users, those who provide an email address and optional password and (even more) lightweight users who provide only their name. When lightweight users return to my site --even after closing their browser-- their name should be automatically remembered and they should be automatically signed in with their lightweight permissions. Given that name may not be unique, I want to sign the lightweight users in based on their user ID.
(Lightweight users can become full users by adding their email address later.)
I am using Devise, and my user.rb file includes:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
def password_required?
false
end
def email_required?
false
end
def remember_me
true
end
In the devise.rb initializer, I have tried setting
config.authentication_keys = [ :user_id ]
but it didn't have an effect other than breaking authentication for those users who have an email address.
With config.authentication_keys = [:email], returning users who have provided an email address are successfully logged into the site when they return even if the browser is restarted/session cookie is destroyed. However, returning users with just a name are forgotten when the browser is restarted. In both cases a remember_user_token cookie is present.
Looking at https://github.com/plataformatec/devise/wiki/How-To:-Allow-users-to-sign-in-using-their-username-or-email-address, I may need to overwrite Devise's find_for_database_authentication method, but I'm not sure what to put in that or if that will be enough; I've tried some variations of that without success.
Finally figured this out; here is the answer in case others have the same issue.
The relevant sign-in process happens in the Rememberable module of Devise.
Devise stores the saved user information between sessions in the remember_user_token cookie. The cookie contains both the user ID and a remember token.
If the email and password are both blank, the remember token will also be blank, causing an internal Devise comparison (secure_compare) to fail. This will result in the session being lost and the remember_user_token cookie to be destroyed.
To fix this, you can set a temporary password for users that don't have one. One approach is the following.
class RegistrationsController < Devise::RegistrationsController
def sign_up_params
new_params = devise_parameter_sanitizer.sanitize(:sign_up)
# If no password is supplied for new user, create one
# This is needed because Devise requires a password for Rememberable to work,
# even if password_required? is set to false in the User model.
if (new_params[:password] == nil)
new_params[:password] = Devise.friendly_token
end
# return the modified (and further sanitized) params list
new_params
end
end
It's up to you, depending on what you're trying to do, whether you want to let the user know about the temporary password they have. Or you could have them reset it if they later add an email address which will also result in them confirming their email address.
I'm writing an API aside with an web page. I want to have Oauth2 login so i can keep a session from the mobile device, i've already install the GEM doorkeeper and run the migration how it's explained on this site.
where i'm getting stuck is in the resource_owner_from_credentials parts, since i have an User model which has authenticate method given by the has_secure_password helper from rails. this is how my /config/initializers/doorkeeper.rb file looks like
Doorkeeper.configure do
# Change the ORM that doorkeeper will use.
# Currently supported options are :active_record, :mongoid2, :mongoid3, :mongo_mapper
orm :active_record
# This block will be called to check whether the resource owner is authenticated or not.
resource_owner_from_credentials do
User.find_by_email(params[:email]).authenticate(params[:password])
end
##lots of comments
end
and when go to
localhost:3000/oauth/authorize
i get this:
config/initializers/doorkeeper.rb:8:in `block (2 levels) in <top (required)>'
then i tried:
http://127.0.0.1:3000/oauth/authorize?email=puca#gmail.com&password=porche
and the same
what i'm i doing wrong? how should i configuresource_owner_authenticator block? how do i get the token?
As per this doorkeeper wiki page you need to send a POST request to /oauth/token API with the following params:
{
"grant_type" : "password",
"username" : "user#example.com",
"password" : "sekret"
}
When this request is processed, doorkeeper calls the resource_owner_from_credentials block and passes the params to it. So you have access to the param named username and not email.
To summarize, fix the API endpoint to /oauth/token , change params[:email] to params[:username] and everything should work.
Using Rails 4 and Devise 3, I would like to have different registration pages based on the URL my user is given.
As an example, each of the following should be directed to a different view that acts as devise registration.
www.mydomain.com <-- current root to registrations#new
www.mydomain.com/user_type_1
www.mydomain.com/user_type_2
www.mydomain.com/user_type_3
How would I do this? I can copy app/views/devise/registrations/new.html.erb to capture the form but how would I make the routing work?
My routes are currently set up as such (I close each session so the user can sign up a friend, but that is not relevant to this question)
devise_scope :user do
authenticated :user do
root :to => 'devise/sessions#destroy', as: :authenticated_root
end
unauthenticated :user do
root :to => 'devise/registrations#new', as: :unauthenticated_root
end
end
So you want three different url paths that point to three different views, but you want the forms to all send their info to the same REST endpoint in the same controller (users#create)? That sounds simple. You have GET requests to get the html/erb files for each registration page (welcome#index, welcome#cool, welcome#coolest), and routes for each to send the GET request to the right controller action.
Then you set up the forms to all send their info to POST to users#new, and one route from there.
Does that make sense?
I want foo.com/ to show the landing page when the user isn't logged in, and foo.com/ to show the dashboard of the user when the user is logged in, just like in Facebook.
I was going to do it the following way:
def index
if user_signed_in?
#posts = current_user.posts
render 'home/dashboard'
else
render 'home/landing'
end
end
But then quickly realized that I'd need to use before_filter :authenticate_user! in order to get current_user, so Devise will require to sign in.
Maybe there's a way to do this more cleanly using routing. Please advice.
authenticated :user do
root to: "users#index", as: :authenticated_root
end
unauthenticated do
root to: "main#index"
end
https://github.com/plataformatec/devise/issues/2393#issuecomment-17298414