redirecting from http://example.com to https://example.mysite.com - redirect

This question has been asked in various permutations, but I haven't found the right combination that answers my particular question.
The configuration
Rails 3.1 (allowing me to use force_ssl in my ApplicationController)
Hosted on Heroku Cedar (so I can't touch the middleware)
My SSL certs are registered for secure.example.com
I've already added force_ssl to my ApplicationController, like this:
# file: controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
force_ssl
end
The problem
Currently, if a user navigates to http://example.com, force_ssl switches to SSL, but since it's NOT secure.example.com, it presents a warning about an unverified security cert because it's using the default Heroku cert.
(I've verified that navigating to http://secure.example.com properly redirects to https://secure.example.com and uses the proper security cert. That's good.)
The question
How do I force http://www.example.com/anything and http://example.com/anything to redirect to http://secure.example.com/anything? (I'm assuming that force_ssl will handle the switch from http to https.) Since I cannot touch the middleware (recall that this is Heroku hosting), I assume I can do something like:
# file: controllers/application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery
force_ssl
before_filter :force_secure_subdomain
private
def force_secure_subdomain
redirect_to(something...) unless request.ssl?
end
end
... but I haven't sufficiently grokked redirect_to and the request object to know what to write for something.... (I want to be sure that it handles query params, etc.)

you can redirect to a different hostname by doing the following:
# file: controllers/application_controller.rb
class ApplicationController < ActionController::Base
force_ssl :host => "secure.example.com"
end
see: rails force_ssl source for more info

You should have a look at rack-rewrite - it's essentially Apache re-write but in Ruby form, and usable on Heroku.
This will allow you to create all sorts of Rack level rules and what redirections etc should occur and when.

Related

Rails 6 ActionMailer previews and http basic authentication

I have the following ActionMailer configuration in production.rb:
unless ENV['APP_NAME'] == 'application-production'
config.action_mailer.preview_path = Rails.root.join('test/mailers/previews')
config.action_mailer.show_previews = true
end
The problem is, non-production apps, such as the staging app, should have http authentication for the whole domain, including the mailer preview path '/rails/mailers' which is now accessible without auth. What's the missing configuration?
EDIT: I tried adding an initializer as per this answer: https://stackoverflow.com/a/44923157/2116456. I would like to use ActionController::Base.http_basic_authenticate_with in the initializer, but it's not available
Okay, I found a way to do what I needed:
I set up an initializer: 'initializers/mailer_previews.rb' with the following:
if Rails.application.config.action_mailer.show_previews
Rails::MailersController.prepend_before_action do
head :forbidden unless authenticate_or_request_with_http_basic('Plz login') do |username, password|
username == ENV['AUTH_NAME'] && password == ENV['AUTH_PASSWORD']
end
end
end
Thanks to #prcu for pointing me in the right direction (see this post)

Rails - How to authorise user with third party api

I'm setting up some authentication in my rails application. Only thing is I want to log in a user based on their credentials with another API.
The application will have to send a POST request with their username and password in the body to the API and if the request is successful then the user authorised.
I'm having trouble trying to do this with devise, I'm just looking for tips you guys have in order to implement this.
Thanks!
Devise allows you to define custom strategies for authentication. You can therefore create a new strategy to handle it. Database Authentication is one of the strategy already defined at Devise. You can check the source here
A rough idea of your strategy could like this.
Create a file at config/initializers/external_authenticatable.rb and define the strategy
require 'devise/strategies/database_authenticatable'
module Devise
module Strategies
class ExternalAuthenticatable < DatabaseAuthenticatable
def authenticate!
resource = password.present? && mapping.to.find_for_database_authentication(authentication_hash)
if validate(resource){ valid_credentials?(resource) }
remember_me(resource)
resource.after_database_authentication
success!(resource)
end
fail(:not_found_in_database) unless resource
end
def valid_credentials?(resource)
request_params = { email: resource.email, password: password }
# Make your post request here and return true false using authentication_hash
end
end
end
end
Now we need to inform devise that we want to use this strategy first before any other defaults. This can be done by editing /config/initializers/devise.rb
config.warden do |manager|
manager.strategies.add(:external, Devise::Strategies::ExternalAuthenticatable)
manager.default_strategies(:scope => :user).unshift :external
end
Restart your Rails application and you are done.

SoapUI 5.0 Create cookie

I'm trying to run a REST project and have inserted securitytoken and session into my header.
But I get an errormessage telling me that a cookie is missing (since my service needs a cookie to run successful).
I have tried to do this with Groovy:
import com.eviware.soapui.impl.wsdl.support.http.HttpClientSupport
def myCookieStore = HttpClientSupport.getHttpClient().getCookieStore()
import org.apache.http.impl.cookie.BasicClientCookie
def myNewCookie = new BasicClientCookie("mycookiename", "mycookievalue")
myNewCookie.version = 1
myNewCookie.domain = "my domain as IP"
myCookieStore.addCookie(myNewCookie)
But its still throwing me the same errormessage.
Are there any solution to inject a cookie as a header in SoapUI 5.0?
I would have like to add this as a comment, but I don't have 50 reputation yet.
Don't know if you are still working on this, but anyway:
Like Rao says it seems like you want to work in a session with a negotiated token. You can go three ways with this in soapui.
Like you propose: create the cookie and the values from scratch. That would be a good use case when you want to test which values are going to pass and which values or combos thereof will return errors or different kinds of messages.
If you want to test anything else then the headers, then you can load a certificate, go to the authentication link and retrieve your tokens and session IDs from the headers in the Set-Cookies as proposed by Rao.
Option number three, my personal favourite when testing other things than headers, is to trust SoapUI to take care of it. You can do this by setting the test case to remember your session. You can set this setting in the testcase settings menu. It is called something the likes of 'Maintain http session'.
Remark: In soapui you can modularize tests. You could for example make a testcase for the authentication in an 'util' test suite. This because you can then disable the util test suite to prevent it from running as a dead-weight test. You can then call to this testcase anywhere to invoke the authentication procedure. For this to work you have to set the settings for the 'Run Testcase' (it is named somehting like that) to 'transport the http session to and from this test case' and, like before, set the parent testcase to 'Maintain HTTP Session'. More info on modularization: https://www.soapui.org/functional-testing/modularizing-your-tests.html.
For the security certificate import, check this smartbear example: https://www.soapui.org/resources/blog/ws-security-settings.html

Why is the authorization context with multiple PSGI applications in Catalyst not working?

I have tow cascading Plack middleware applications(app1, app2), app1 is the front application. I followed these tutorials:
http://advent.plackperl.org/2009/12/day-10-using-plack-middleware.html
http://advent.plackperl.org/2009/12/day-19-cascade-multiple-applications.html
This is my code:
use Plack::App::Cascade;
use Plack::App::URLMap;
use lib "/var/www/app1/lib",
"/var/www/app2/lib";
use app1;
use app2;
my $app1 = app1->psgi_app(#_);
my $app2 = app2->psgi_app(#_);
my $app_map1 = Plack::App::URLMap->new;
$app_map2->mount( '/' => $app1 );
my $app2 = Plack::App::URLMap->new;
$app2->mount( '/app2' => $app2 );
Plack::App::Cascade->new(apps => [ $app_map1, $app_map2 ])->to_app;
Until now everything is ok, I added also the authentication functionality, and for that i used these two catalyst modules: Catalyst::Plugin::Authentication and Catalyst::Plugin::Authorization::Abilities.
The authentication part is working fine for the two applications (user logged from app1), but I got a problem for the authorization part just for app2. When I try to figure out, it was the context variable $c. The app1 $c variable was not the same as app2. After authentication (from app1) I got a user object $c->user, but for the second application I had a new $c created and the $c->user is not found.
So how can these two applications get the same context $c?
I find the solution but before that let me explain the situation:
PSGI with muti middelware applications have same limitation. Each middleware behaves as a separate application and each one create its own session. In case, we have the authentication feature(applied for all middelware) we got a prob here. like the example above, the app1 had the session of the authenticated user but app2 had just an anonymous session.
So to fixe it. I create a shared memory to store sessions. For that, me must change Catalyst::Plugin::Session::Store::File with Catalyst::Plugin::Session::Store::FastMmap for app1 and app2.
Then add this config in app2.pm:
'Plugin::Session' => {
cookie_name => 'app1_session',
storage => '/tmp/app1/session_data',
}

Multiple instances of Sinatra::Base applications with different configurations

I developed a Rack application based on Sinatra::Base. Now I would like to use many instances of it, each with a slightly different configuration, in a single Rack application.
My rackup should look like
use Rack::Lint
map '/mel' do
run Site.new('/home/mel/site').app
end
map '/pub' do
run Site.new('/pub').app
end
The Site class collects various parameters (in this example only the root dir) and does some preparatory work. The #app method should return a Server object that holds a reference to the served Site instance.
This is an example of the Site and Server code:
class Site
def initialize(root_dir)
#root_dir = root_dir
# ... set up things ...
end
def app
# This is where a new Server Rack application should be created
return Server.new { |server| server.set :site, self }
end
end
class Server < Sinatra::Base
before do
#content = settings.site.all_files
end
get /(.*)/ do |url_path|
# do things...
end
end
The problem with this code is that the #app method does not return a valid Rack application.
What should I do in #app to return a new, configured Server Rack application?
This is a way to make it work suggested by "carloslopes" on #sinatra.
The Site#app method becomes
class Site
def app
# This is where a new Server object should be created
return Server.new(self)
end
end
and the Server objects get their parameters via instance variables:
class Server < Sinatra::Base
def initialize(site)
super()
#site = site
end
before do
#content = #site.all_files
end
get /(.*)/ do |url_path|
# do things...
end
end
Edit: made community wiki so that other can make the solution even better and share the credit.