Authenticate static files with Devise? - devise

I have a static Jekyll support page on my site served in /public/support. The main rails app is behind devise - the whole thing. If you are not authenticated you get kicked back to the login. Can I 'hide' this static site behind the Devise authentication - i.e. only allow access to the static pages when authenticated?

I ended up finding this:
https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-subrequest-authentication/
In my NGINX config I have this:
location /support {
auth_request /auth;
auth_request_set $auth_status $upstream_status;
error_page 403 https://$host;
}
In my application controller I have:
before_action :authenticate_user!, except: :auth
This by-passes Devise.
In routes:
get '/auth', to: 'errors#auth'
It just made sense to add it to my existing custom errors controller.
Then in the controller:
def auth
user_signed_in? ? render(status: 200, layout: :blank) : render(status: 403, layout: :blank)
end
The blank layout has no content - just a <%= yield %>.
If the user has an open Devise session they can access the support site otherwise they get redirected to the login page (default for Devise).

Related

Flask app-setting up page dependency for LDAP login

I have 2 webpages /login and /index . I could set up dependency for entering /index page once login is authenticated from LDAP using the following view function and it works perfectly with this:
#app.route('/index',methods=['GET','POST'])
def index():
return render_template('index.html')
#app.route('/')
#app.route('/login',methods=['GET', 'POST'])
def login():
error=None
if request.method =='POST':
s = Server('appauth.corp.domain.com:636', use_ssl=True, get_info=ALL)
c=Connection(s,user=request.form['username'],password=request.form['password'],check_names=True, lazy=False,raise_exceptions=False)
c.open()
c.bind()
if request.form['username'] not in users and (c.bind() != True) is True:
error='Invalid credentials. Please try again'
else:
return redirect(url_for('index'))
return render_template('login.html',error=error)
Excuse the indentation for the first line and c=Connection(s,user=request.form['username'],password=request.form['password'],check_names=True, lazy=False,raise_exceptions=False)
`
I am able to access /index page by bypassing the login page. I found that there is a way to set up a decorator #login_required using flask_login. But that would involve setting up a local database using SQLAlchemy . Is there a easier way of doing that as I would need to modify my login log otherwise.
In the login page i am calling index.html, I am using this as my base.hml
`{% extends 'index.html' %}
Implemented it successfully using sessions. This is exactly what is needed for this
http://flask.pocoo.org/docs/0.11/quickstart/#sessions

Rack middleware fails to redirect on authentication in Sinatra

Why does the Rack middleware fail to redirect when coupled with default GET and POST login routes and 401 handling in the Sinatra app?
Relevant Shield middleware extract :
module Shield
class Middleware
attr :url
def initialize(app, url = "/login")
#app = app
#url = url
end
def call(env)
tuple = #app.call(env)
if tuple[0] == 401
[302, headers(env["SCRIPT_NAME"] + env["PATH_INFO"]), []]
else
tuple
end
end
private
def headers(path)
{ "Location" => "%s?return=%s" % [url, encode(path)],
"Content-Type" => "text/html",
"Content-Length" => "0"
}
end
def encode(str)
URI.encode_www_form_component(str)
end
end
end
View full source code (104 lines/2.8kb).
Here a relevant extract of the Sinatra app:
# application_controller.rb
class ApplicationController < Sinatra::Base
helpers Shield::Helpers
use Shield::Middleware, "/login"
...
get '/noway' do
error(401) unless authenticated(User)
erb :app_noway
end
get '/login' do
erb :login
end
post "/login" do
if login(User, params[:login], params[:password])
remember(authenticated(User)) if params[:remember_me]
redirect(params[:return] || "/")
else
redirect "/login"
end
end
end
Full source code (basic app displaying the problem behavior), for easy and immediate perusal: https://github.com/shieldtest/shieldtest
The repository is ready for a "clone and rackup" with database, env and all. Login credentials; email: shield#example.org, password: shield.
Problem When accessing a protected route (/noway), the middleware injects a authentication process, as intended. But after the successful autentication, the subsequent redirect always defaults to root, instead of the return URL for the protected page (/noway).
Solution needed The protected page (/noway) should be redirected to automatically after authenticating successfully via Shield.
Visual walk-through
Step 1 (below): At the Sinatra main page. Click link to protected page (/noway)
Step 2 (below): Redirected to /login correctly, as no user is authenticated. Enter correct login credentials correctly.
PROBLEM BEHAVIOR - redirected to main instead of the protected pageStep 3A (below): After entering correct login credentials: sent back to main page (again)
TESTING LOGIN - protected page is accessible now (manually, by clicking page again)Step 4 (below): At the main page. Click the protected page (/noway) again => Access granted
The params[:return] was never forwarded to the POST request, it seems.
So, a 'dirty fix' would be to grab the return params and pass it via the login form to the POST request. This yields the desired behavior:
#login.rb
...
<% if params[:return] %>
<input type='hidden' name='redirect' value="<%= params[:return] %>">
<% end %>
...
And then redirecting to the redirect params from the login form:
#application_controller.rb
post "/login" do
if login(User, params[:login], params[:password])
...
redirect to params[:redirect] || "/"
...
end
end
Still, I would have preferred to understand why the middleware didn't perform as expected and how to fix/store this return params via the Rack middleware.

Sign in redirects to home page instead of staying on same page

I installed devise and it is working properly but the sign in redirect. When user signs in from any page of app, Devise redirects user to home instead of redirecting on same page. I tried implementing How_to solutions of devise but no help.
I wrote in application_controller:
def after_sign_in_path_for(resource)
current_user_path
end
But it gives error:
undefined local variable or method `current_user_path' for #<Devise::SessionsController:0xaeacc34>
When i write:
def after_sign_in_path_for(resource)
current_user_path
end
It gives :
undefined method `user_url'
Whats the solution for this problem? Can any body help in this?
You can use request.referer
def after_sign_in_path_for(resource_or_scope)
request.referer
end
You need to redirect to somewhere else in which scenerio(error or success)? Usually after_sign_in_path_for used after user logged in successfully. SO:
if you haven't override devise default functionality then use below code for navigate control to specific custom page. current_user is also accessible in this action.
def after_sign_in_path_for(resource)
scope = Devise::Mapping.find_scope!(resource)
scope_path = :"#{scope}_root_path"
respond_to?(scope_path, true) ? send(scope_path) : root_url
end
Update:
Another example is as follows:
def after_sign_in_path_for(resource_or_scope)
current_user.admin? ? dashboard_admin_home_index_path : current_user.sign_in_count >= 1 ? "/home/dashboard" : "/#{current_user.role}/dashboard"
end

Handling complex post-login redirection logic in Rails

I have a rails app that needs to redirect users to different pages based on some criteria after they log in (using Devise & OmniAuth). This logic could be pseudo-coded like this:
if the user is an admin
if no url was specified before login (original_uri)
- redirect to admin panel
else
- redirect to original_uri
else
if the user filled up his profile data
if no url was specified before login
- redirect to user's home page
else
if original_uri is allowed (not restricted to that user)
- redirect to original_uri
else
- redirect to user's home page
else
- redirect to profile page
or as an rspec integration example:
describe "complex routing" do
context "user is an admin" do
let(:user) { create(:admin) }
context "an original URL was specified before login" do
it "redirects to the original URL"
end
context "no original URL was specified" do
it "redirects to the admin panel"
end
end
context "user is not an admin" do
let(:user) { create(:user, :completed_profile => false) }
context "with complete profile info" do
before(:each) { user.completed_profile = true }
context "an original URL was specified before login" do
it "redirects to original URL if not restricted"
it "redirects to home page if URL is restricted"
end
context "no original URL was specified" do
it "redirects to home page"
end
end
context "with incomplete profile" do
it "redirects to profile page"
end
end
end
As can be seen, this gets quite complex and not very obvious (or easy to test). In addition, the thought of this sitting in a before_filter :decide_routing as a method call makes me cringe.
What would be a good way to abstract this and make this cleaner, testable and simpler to manage in the future (in case more logic needs to be added or changed)?
Any thoughts will be great - thanks.
Does this does it?
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :authenticate_user!
protected
def after_sign_in_path_for(resource)
# if user is not active, redirect him so he completes registration
if resource.active?
super
else
# complete_the_effing_registration_path
end
end
end

Rails 3 with Devise - Unauthorized redirect with jQuery Mobile

Application controller:
I use view inheritance instead of a different format (like :mobile)
before_filter :subdomain_view_path
def subdomain_view_path
prepend_view_path "app/views/mobile" if request.server_name.include?("mobile") || request.user_agent =~ /Mobile|iPad/
end
Shows controller
class ShowsController < ApplicationController
before_filter :authenticate_user!
end
When I go directly to /shows in my browser, I get redirected to the login page correctly.
However, I get a 401 Unauthorized when clicking a link (ajax) to that page.
How can I solve this? It would be cool to keep this ajax loading of pages.
Putting this in you application.js may help you:
// Set up a global AJAX error handler to handle the 401
// unauthorized responses. If a 401 status code comes back,
// the user is no longer logged-into the system and can not
// use it properly.
$.ajaxSetup({
statusCode: {
401: function() {
// Redirect the to the login page.
location.href = "/login";
}
}
});
Source: http://rubythings.blogspot.de/2011/10/ajax-redirects-with-devise.html