diff --git a/Gemfile b/Gemfile index b5cb28aa4..a49401596 100644 --- a/Gemfile +++ b/Gemfile @@ -41,7 +41,9 @@ gem 'lesstile', '~> 1.1.0' gem 'formtastic' gem 'will_paginate', '~> 3.0.2' gem 'exception_notification', '~> 2.5.2' -gem 'open_id_authentication' +gem 'omniauth' +gem 'omniauth-google-oauth2' +gem 'omniauth-openid' # Bundle gems for the local environment. Make sure to # put test-only gems in this group so their generators diff --git a/Gemfile.lock b/Gemfile.lock index cd7a1a7b3..f870fb3ee 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -59,15 +59,19 @@ GEM actionmailer (>= 3.0.4) factory_girl (4.2.0) activesupport (>= 3.0.0) + faraday (0.9.1) + multipart-post (>= 1.2, < 3) formtastic (2.2.1) actionpack (>= 3.0) gherkin (2.12.0) multi_json (~> 1.3) + hashie (3.4.1) hike (1.2.3) i18n (0.6.4) jquery-rails (3.0.4) railties (>= 3.0, < 5.0) thor (>= 0.14, < 2.0) + jwt (1.4.1) launchy (2.3.0) addressable (~> 2.3) lesstile (1.1.0) @@ -78,9 +82,29 @@ GEM minitest (4.7.5) multi_json (1.7.7) multi_test (0.0.2) + multi_xml (0.5.5) + multipart-post (2.0.0) nokogiri (1.5.10) - open_id_authentication (1.1.0) - rack-openid (~> 1.3) + oauth2 (1.0.0) + faraday (>= 0.8, < 0.10) + jwt (~> 1.0) + multi_json (~> 1.3) + multi_xml (~> 0.5) + rack (~> 1.2) + omniauth (1.2.2) + hashie (>= 1.2, < 4) + rack (~> 1.0) + omniauth-google-oauth2 (0.2.6) + omniauth (> 1.0) + omniauth-oauth2 (~> 1.1) + omniauth-oauth2 (1.2.0) + faraday (>= 0.8, < 0.10) + multi_json (~> 1.3) + oauth2 (~> 1.0) + omniauth (~> 1.2) + omniauth-openid (1.0.1) + omniauth (~> 1.0) + rack-openid (~> 1.3.1) polyglot (0.3.3) rack (1.5.2) rack-openid (1.3.1) @@ -167,7 +191,9 @@ DEPENDENCIES jruby-openssl lesstile (~> 1.1.0) nokogiri (~> 1.5.0) - open_id_authentication + omniauth + omniauth-google-oauth2 + omniauth-openid rack-openid rails (~> 4.0.0) rspec diff --git a/app/assets/javascripts/common.js b/app/assets/javascripts/common.js index 785d014ec..1f7b1037e 100644 --- a/app/assets/javascripts/common.js +++ b/app/assets/javascripts/common.js @@ -24,4 +24,5 @@ jQuery.ajaxSetup({ // jQuery extensions jQuery.prototype.any = function(callback) { return (this.filter(callback).length > 0) -} \ No newline at end of file +} + diff --git a/app/controllers/admin/sessions_controller.rb b/app/controllers/admin/sessions_controller.rb index ac58701fa..e8b923d1b 100644 --- a/app/controllers/admin/sessions_controller.rb +++ b/app/controllers/admin/sessions_controller.rb @@ -1,40 +1,42 @@ class Admin::SessionsController < ApplicationController skip_before_filter :verify_authenticity_token, :only => :create - before_filter :verify_authenticity_token_unless_openid, :only => :create + before_filter :verify_authenticity_token_unless_using_open_id, :only => :create layout 'login' def show - if using_open_id? - create - else - redirect_to :action => 'new' - end + redirect_to :action => 'new' end def new + flash.now[:error] = params[:message] if params[:message] # OmniAuth error message. end def create - return successful_login if allow_login_bypass? && params[:bypass_login] - - if params[:openid_url].blank? && !request.env[Rack::OpenID::RESPONSE] - flash.now[:error] = "You must provide an OpenID URL" - render :action => 'new' - else - authenticate_with_open_id(params[:openid_url]) do |result, identity_url| - if result.successful? - if enki_config.author_open_ids.include?(URI.parse(identity_url)) - return successful_login - else - flash.now[:error] = "You are not authorized" - end + return successful_login if allow_login_bypass? && params[:bypass_login] == '1' + + if request.env['omniauth.auth'].present? + case request.env['omniauth.auth'][:provider] + when OMNIAUTH_GOOGLE_OAUTH2_STRATEGY + if enki_config.author_google_oauth2_email == request.env['omniauth.auth'][:info][:email] + save_auth_details(request.env['omniauth.auth']) + return successful_login + else + return show_not_authorized + end + when OMNIAUTH_OPEN_ID_ADMIN_STRATEGY + if enki_config.author_open_ids.include?(URI.parse(request.env['omniauth.auth'][:uid])) + save_auth_details(request.env['omniauth.auth']) + return successful_login else - flash.now[:error] = result.message + return show_not_authorized end - render :action => 'new' + else + raise ArgumentError, "The value returned from request.env['omniauth.auth'][:provider] is unknown." end end + + show_not_authorized end def destroy @@ -44,6 +46,21 @@ def destroy protected + def show_not_authorized + flash.now[:error] = 'You are not authorized' + render :action => 'new' + end + + def save_auth_details(auth_response) + OmniAuthDetails.create( + :provider => auth_response[:provider], + :uid => auth_response[:uid], + :info => auth_response[:info], + :credentials => auth_response[:credentials], + :extra => auth_response[:extra] + ) + end + def successful_login session[:logged_in] = true redirect_to(admin_root_path) @@ -53,9 +70,20 @@ def allow_login_bypass? %w(development test).include?(Rails.env) end - def verify_authenticity_token_unless_openid + def verify_authenticity_token_unless_using_open_id verify_authenticity_token unless using_open_id? end + def using_open_id? + if request.env['omniauth.auth'].present? + if request.env['omniauth.auth'][:provider] == OMNIAUTH_GOOGLE_OAUTH2_STRATEGY || + request.env['omniauth.auth'][:provider] == OMNIAUTH_OPEN_ID_ADMIN_STRATEGY + return true + end + end + + return false + end + helper_method :allow_login_bypass? end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 150bcfbbc..168ddd9a9 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,10 +1,27 @@ class ApplicationController < ActionController::Base protect_from_forgery + OMNIAUTH_GOOGLE_OAUTH2_STRATEGY = 'google_oauth2' + OMNIAUTH_OPEN_ID_ADMIN_STRATEGY = 'open_id_admin' + OMNIAUTH_OPEN_ID_COMMENT_STRATEGY = 'open_id_comment' + protected def enki_config @@enki_config = Enki::Config.default end + + # Used for OmniAuth routing. + def auth_path(provider, query_string_params = '') + path = "/auth/#{provider.to_s}" + + if !query_string_params.blank? + return path + "?#{query_string_params}" + end + + path + end + helper_method :enki_config + helper_method :auth_path end diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index 7638ae2ad..c0ffeea0f 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -1,12 +1,8 @@ class CommentsController < ApplicationController skip_before_filter :verify_authenticity_token, :only => :create - before_filter :verify_authenticity_token_unless_openid, :only => :create + before_filter :verify_authenticity_token_unless_using_openid, :only => :create include UrlHelper - OPEN_ID_ERRORS = { - :missing => "Sorry, the OpenID server couldn't be found", - :canceled => "OpenID verification was canceled", - :failed => "Sorry, the OpenID verification failed" } before_filter :find_post, :except => [:new] @@ -26,53 +22,44 @@ def new # TODO: Spec OpenID with cucumber and rack-my-id def create - @comment = Comment.new((session[:pending_comment] || comment_params || {}). - reject {|key, value| !Comment.protected_attribute?(key) }) + @comment = Comment.new((session[:pending_comment] || comment_params || {}). + reject { |key, value| !Comment.protected_attribute?(key) }) + @comment.post = @post - session[:pending_comment] = nil - - if @comment.requires_openid_authentication? - session[:pending_comment] = comment_params - authenticate_with_open_id(@comment.author, - :optional => [:nickname, :fullname, :email] - ) do |result, identity_url, registration| - if result.status == :successful - @comment.post = @post - - @comment.author_url = @comment.author - @comment.author = ( - registration["fullname"] || - registration["nickname"] || - @comment.author_url - ).to_s - @comment.author_email = ( - registration["email"] || - @comment.author_url - ).to_s - - @comment.openid_error = "" - session[:pending_comment] = nil - else - @comment.openid_error = OPEN_ID_ERRORS[ result.status ] - end - end - else + if !@comment.requires_openid_authentication? @comment.blank_openid_fields - end - - # #authenticate_with_open_id may have already provided a response - unless response.headers[Rack::OpenID::AUTHENTICATE_HEADER] - if @comment.save - redirect_to post_path(@post) - else - render :template => 'posts/show' + save_comment_or_show_error + else + if request.env['omniauth.auth'].nil? && params[:message].blank? # Begin auth. + session[:pending_comment] = comment_params + session[:post_id] = @post.id + redirect_to auth_path(:open_id_comment, "openid_url=#{@comment.author}") + elsif !request.env['omniauth.auth'].nil? # Process success response. + @comment.author_url = request.env['omniauth.auth'][:uid] + @comment.author = request.env['omniauth.auth'][:info][:name] + @comment.author_email = request.env['omniauth.auth'][:info][:email] || '' + @comment.openid_error = '' + save_comment_or_show_error + else # Process error response. + @comment.openid_error = params[:message] + save_comment_or_show_error end end end private + def save_comment_or_show_error + if @comment.save + session[:pending_comment] = nil + session[:post_id] = nil + redirect_to post_path(@post) + else + render :template => 'posts/show' + end + end + def comment_params params.require(:comment).permit(:author, :body) end @@ -83,9 +70,21 @@ def find_post @post = Post.find_by_permalink(*[:year, :month, :day, :slug].map {|x| params[x] }) + + rescue ActiveRecord::RecordNotFound + @post = Post.find(session[:post_id]) end - def verify_authenticity_token_unless_openid + def verify_authenticity_token_unless_using_openid verify_authenticity_token unless using_open_id? end + + def using_open_id? + if !request.env['omniauth.auth'].nil? && + request.env['omniauth.auth'][:provider] == OMNIAUTH_OPEN_ID_COMMENT_STRATEGY + return true + end + + return false + end end diff --git a/app/models/omni_auth_details.rb b/app/models/omni_auth_details.rb new file mode 100644 index 000000000..edd599f87 --- /dev/null +++ b/app/models/omni_auth_details.rb @@ -0,0 +1,5 @@ +class OmniAuthDetails < ActiveRecord::Base + serialize :info, Hash + serialize :credentials, Hash + serialize :extra, Hash +end diff --git a/app/views/admin/sessions/new.html.erb b/app/views/admin/sessions/new.html.erb index 192889a3e..cf3dac98a 100644 --- a/app/views/admin/sessions/new.html.erb +++ b/app/views/admin/sessions/new.html.erb @@ -1,10 +1,16 @@

<%= link_to(enki_config[:title], '/') %>

<% if flash[:error] %>

<%= flash[:error] %>

<% end %> -<%= form_tag(admin_session_path) do -%> -

Stop! Who are you?

-

<%= text_field_tag 'openid_url' %>

- <% if allow_login_bypass? -%> -

<%= check_box_tag 'bypass_login' %>

- <% end -%> -

<%= submit_tag("Login with OpenID") %>

+

Stop! Who are you?

+<% if allow_login_bypass? -%> + <%= form_tag(admin_session_path) do -%> + <%= hidden_field_tag 'bypass_login', '1' -%> +

<%= submit_tag('Bypass credentials check') %>

+ <%- end %> +<%- end %> +<%= form_tag(auth_path(:google_oauth2)) do -%> +

<%= submit_tag('Login with Google OpenID Connect') %>

+<% end -%> +<%= form_tag(auth_path(:open_id_admin)) do -%> +

<%= text_field_tag 'openid_url', nil, placeholder: 'Enter your OpenID URL' %>

+

<%= submit_tag('Login with OpenID') %>

<% end -%> diff --git a/app/views/layouts/login.html.erb b/app/views/layouts/login.html.erb index 6f8e07e27..d806dd573 100644 --- a/app/views/layouts/login.html.erb +++ b/app/views/layouts/login.html.erb @@ -4,6 +4,16 @@ <%= enki_config[:title] %> - Admin Login <%= stylesheet_link_tag 'login' %> + <%= javascript_tag do -%> + // Why is this code here? After a failed OpenID login, second and subsequent tries will cause Rails to throw an + // ActionDispatch::Cookies::CookieOverflow exception when hitting the /auth/open_id_admin path (this path is + // dynamically set by OmniAuth) due to the large amount of stuff passed in from the query string. So let's + // automagically say goodbye to the query string, no one needs it here anyway. + // to the query string. + if (window.location.href.indexOf('/auth/open_id_admin/callback?') > -1) { + window.history.pushState(null, 'Look ma! No query string!', '/auth/open_id_admin/callback'); + } + <% end -%>
diff --git a/config/.gitignore b/config/.gitignore index a13db8249..4f61f48c4 100644 --- a/config/.gitignore +++ b/config/.gitignore @@ -1,2 +1,3 @@ database.yml defensio.yml +google_oauth2.yml diff --git a/config/application.rb b/config/application.rb index 7aea381a9..beb545878 100644 --- a/config/application.rb +++ b/config/application.rb @@ -6,6 +6,19 @@ Bundler.require(:default, Rails.env) end +# Make google_oauth2.yml values available as ENV values (used with the google_oauth2 OmniAuth strategy). +# If deploying to Heroku, you will need to set the two required ENV values manually for Heroku, for example: +# heroku config:set GOOGLE_CLIENT_ID=my_client_id +# heroku config:set GOOGLE_CLIENT_SECRET=my_client_secret +if File.exists?(File.expand_path('../google_oauth2.yml', __FILE__)) + config = YAML.load(File.read(File.expand_path('../google_oauth2.yml', __FILE__))) + config.merge! config.fetch(Rails.env, {}) + + config.each do |key, value| + ENV[key] ||= value.to_s unless value.kind_of? Hash + end +end + # This configures the base path of routes for the main application. # For example, set to '/blog' to run at http://example.com/blog # It must appear before the Application class body. Initializers run too late. diff --git a/config/enki.yml b/config/enki.yml index cbd1f3ae6..12f42c31c 100644 --- a/config/enki.yml +++ b/config/enki.yml @@ -3,14 +3,22 @@ title: My Enki Blog url: http://enkiblog.com author: - name: Don Alias # For copyright notice and ATOM feeds - email: don@enkiblog.com # Exception emails will go here, and it is used in ATOM feeds - open_id: # These are used to login to the admin area + name: Don Alias # For copyright notice and ATOM feeds + email: don@enkiblog.com # Exception emails will go here, and it is used in ATOM feeds + + # If you want to use the google_oauth2 (Google OpenID Connect) OmniAuth strategy to login to the admin area, + # google_oauth2_email should match the email of your OpenID Connect identity + google_oauth2_email: "you@your-openid-connect-domain.com" + + # If you want to use OpenID (which is distinct from OpenID Connect) to login to the admin area, open_id should contain + # your OpenID URL(s) + open_id: - http://enkiblog.com - http://secondaryopenid.com # Delete the following section if your site will not be acting as an OpenID delegate (http://wiki.openid.net/Delegation) # If you're deploying with mongrel, make sure you read http://rhnh.net/2008/04/13/nginx-openid-delegation-and-yadis +# Note that OpenID Connect does not support delegation open_id_delegation: server: http://www.myopenid.com/server delegate: http://username.myopenid.com diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb new file mode 100644 index 000000000..c70339434 --- /dev/null +++ b/config/initializers/omniauth.rb @@ -0,0 +1,17 @@ +require 'omniauth-openid' +require 'openid/store/filesystem' + +OmniAuth.config.logger = Rails.logger + +# Uncomment this if you want OmniAuth error responses to work as in production. +#OmniAuth.config.on_failure = Proc.new { |env| +# OmniAuth::FailureEndpoint.new(env).redirect_to_failure +#} + +Rails.application.config.middleware.use OmniAuth::Builder do + provider :google_oauth2, ENV['GOOGLE_CLIENT_ID'], ENV['GOOGLE_CLIENT_SECRET'], { + :scope => 'openid,email' + } + provider :open_id, :name => 'open_id_admin', :store => OpenID::Store::Filesystem.new('/tmp') + provider :open_id, :name => 'open_id_comment', :store => OpenID::Store::Filesystem.new('/tmp') +end diff --git a/config/routes.rb b/config/routes.rb index 4293446eb..7738b3d0d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -30,5 +30,16 @@ get '(:tag)', :as => :posts, :tag => /(?:[A-Za-z0-9_ \.-]|%20)+?/, :format => /html|atom/ end + # OmniAuth routes. + post '/auth/open_id_comment/callback', :to => 'comments#create' + match '/auth/failure' => 'comments#create', + :constraints => lambda { |request| + request.query_parameters[:strategy] == ApplicationController::OMNIAUTH_OPEN_ID_COMMENT_STRATEGY + }, :via => [:get] + post '/auth/open_id_admin/callback', :to => 'admin/sessions#create' + match '/auth/:provider/callback', :to => 'admin/sessions#create', :via => [:get, :post] + get '/auth/failure/comments/new', :to => 'comments#new' + get '/auth/failure', :to => 'admin/sessions#new' + root :to => 'posts#index' end diff --git a/db/migrate/20150412102635_create_omni_auth_details.rb b/db/migrate/20150412102635_create_omni_auth_details.rb new file mode 100644 index 000000000..d84e68890 --- /dev/null +++ b/db/migrate/20150412102635_create_omni_auth_details.rb @@ -0,0 +1,13 @@ +class CreateOmniAuthDetails < ActiveRecord::Migration + def change + create_table :omni_auth_details do |t| + t.string :provider, :null => false + t.string :uid, :null => false + t.text :info, :null => false + t.text :credentials + t.text :extra + + t.timestamps + end + end +end diff --git a/db/migrate/20150414113518_drop_open_id_authentication_tables.rb b/db/migrate/20150414113518_drop_open_id_authentication_tables.rb new file mode 100644 index 000000000..55ce5a5cb --- /dev/null +++ b/db/migrate/20150414113518_drop_open_id_authentication_tables.rb @@ -0,0 +1,15 @@ +class DropOpenIdAuthenticationTables < ActiveRecord::Migration + def up + if ActiveRecord::Base.connection.table_exists? 'open_id_authentication_associations' + drop_table 'open_id_authentication_associations' + end + + if ActiveRecord::Base.connection.table_exists? 'open_id_authentication_nonces' + drop_table 'open_id_authentication_nonces' + end + end + + def down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/db/schema.rb b/db/schema.rb index 272b7a678..b21724153 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20110709024316) do +ActiveRecord::Schema.define(version: 20150414113518) do create_table "comments", force: true do |t| t.integer "post_id", null: false @@ -27,19 +27,14 @@ add_index "comments", ["created_at"], name: "index_comments_on_created_at" add_index "comments", ["post_id"], name: "index_comments_on_post_id" - create_table "open_id_authentication_associations", force: true do |t| - t.integer "issued" - t.integer "lifetime" - t.string "handle" - t.string "assoc_type" - t.binary "server_url" - t.binary "secret" - end - - create_table "open_id_authentication_nonces", force: true do |t| - t.integer "timestamp", null: false - t.string "server_url" - t.string "salt", null: false + create_table "omni_auth_details", force: true do |t| + t.string "provider" + t.string "uid" + t.text "info" + t.text "credentials" + t.text "extra" + t.datetime "created_at" + t.datetime "updated_at" end create_table "pages", force: true do |t| diff --git a/lib/enki/config.rb b/lib/enki/config.rb index 826131527..4e160483a 100644 --- a/lib/enki/config.rb +++ b/lib/enki/config.rb @@ -16,6 +16,10 @@ def author_open_ids [self[:author, :open_id]].flatten.map {|uri| URI.parse(uri)} end + def author_google_oauth2_email + [self[:author, :google_oauth2_email]] + end + def self.default Enki::Config.new(default_location) end diff --git a/spec/controllers/admin/sessions_controller_spec.rb b/spec/controllers/admin/sessions_controller_spec.rb index df18b5e3b..777597c2b 100644 --- a/spec/controllers/admin/sessions_controller_spec.rb +++ b/spec/controllers/admin/sessions_controller_spec.rb @@ -73,73 +73,86 @@ @controller.instance_eval { flash.extend(DisableFlashSweeping) } end - def stub_open_id_authenticate(url, status_code, return_value) - status = double("Result", :successful? => status_code == :successful, :message => '') + #def stub_enki_config(url, status_code, return_value) + # status = double("Result", :successful? => status_code == :successful, :message => '') + # @controller.stub(:enki_config).and_return(double("enki_config", :author_open_ids => [ + # "http://enkiblog.com", + # "http://secondaryopenid.com" + # ].collect {|uri| URI.parse(uri)} + # )) + # @controller.should_receive(:authenticate_with_open_id).with(url).and_yield(status,url).and_return(return_value) + #end + def stub_auth_response(auth_response) + request.env["omniauth.auth"] = auth_response + end + def stub_enki_config @controller.stub(:enki_config).and_return(double("enki_config", :author_open_ids => [ "http://enkiblog.com", "http://secondaryopenid.com" - ].collect {|uri| URI.parse(uri)} + ].collect {|uri| URI.parse(uri)}, + :author_google_oauth2_email => "you@your-openid-connect-domain.com" )) - @controller.should_receive(:authenticate_with_open_id).with(url).and_yield(status,url).and_return(return_value) end describe "with invalid URL http://evilman.com and OpenID authentication succeeding" do before do - stub_open_id_authenticate("http://evilman.com", :successful, false) - post :create, :openid_url => "http://evilman.com" + stub_enki_config + stub_auth_response({ :provider => ApplicationController::OMNIAUTH_OPEN_ID_ADMIN_STRATEGY, + :uid => "http://evilman.com" }) + + post :create end it_should_behave_like "not logged in" end describe "with valid URL http://enkiblog.com and OpenID authentication succeeding" do before do - stub_open_id_authenticate("http://enkiblog.com", :successful, false) - post :create, :openid_url => "http://enkiblog.com" + stub_enki_config + stub_auth_response({ :provider => ApplicationController::OMNIAUTH_OPEN_ID_ADMIN_STRATEGY, + :uid => "http://enkiblog.com" }) + + post :create end it_should_behave_like "logged in and redirected to /admin" end describe "with valid secondary URL http://secondaryopenid.com and OpenID authentication succeeding" do before do - stub_open_id_authenticate("http://secondaryopenid.com", :successful, false) - post :create, :openid_url => "http://secondaryopenid.com" + stub_enki_config + stub_auth_response({ :provider => ApplicationController::OMNIAUTH_OPEN_ID_ADMIN_STRATEGY, + :uid => "http://secondaryopenid.com" }) + + post :create end it_should_behave_like "logged in and redirected to /admin" end - describe "with valid URL http://enkiblog.com and OpenID authentication returning 'failed'" do - before do - stub_open_id_authenticate("http://enkiblog.com", :failed, true) - post :create, :openid_url => "http://enkiblog.com" - end - it_should_behave_like "not logged in" - end - describe "with valid URL http://enkiblog.com and OpenID authentication returning 'missing'" do + describe "with invalid email notyou@someotherdomain.com and Google OpenID Connect authentication succeeding" do before do - stub_open_id_authenticate("http://enkiblog.com", :missing, true) - post :create, :openid_url => "http://enkiblog.com" - end - it_should_behave_like "not logged in" - end - describe "with valid URL http://enkiblog.com and OpenID authentication returning 'canceled'" do - before do - stub_open_id_authenticate("http://enkiblog.com", :canceled, true) - post :create, :openid_url => "http://enkiblog.com" + stub_enki_config + stub_auth_response({ :provider => ApplicationController::OMNIAUTH_GOOGLE_OAUTH2_STRATEGY, + :info => { :email => "notyou@someotherdomain.com" } }) + + post :create end it_should_behave_like "not logged in" end - describe "with no URL" do + describe "with valid email you@your-openid-connect-domain.com and Google OpenID Connect authentication succeeding" do before do - post :create, :openid_url => "" + stub_enki_config + stub_auth_response({ :provider => ApplicationController::OMNIAUTH_GOOGLE_OAUTH2_STRATEGY, + :info => { :email => "you@your-openid-connect-domain.com" } }) + + post :create end - it_should_behave_like "not logged in" + it_should_behave_like "logged in and redirected to /admin" end describe "with bypass login selected" do before do - post :create, :openid_url => "", :bypass_login => "1" + post :create, :bypass_login => "1" end it_should_behave_like "logged in and redirected to /admin" end describe "with bypass login selected but login bypassing disabled" do before do @controller.stub(:allow_login_bypass?).and_return(false) - post :create, :openid_url => "", :bypass_login => "1" + post :create, :bypass_login => "1" end it_should_behave_like "not logged in" end diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb new file mode 100644 index 000000000..c6516c843 --- /dev/null +++ b/spec/controllers/application_controller_spec.rb @@ -0,0 +1,13 @@ +require File.dirname(__FILE__) + '/../spec_helper' + +describe ApplicationController do + describe '#auth_path' do + it 'should return the expected path' do + subject.send(:auth_path, 'an_omniauth_provider_name').should eq('/auth/an_omniauth_provider_name') + end + it 'should return the expected path plus query string' do + subject.send(:auth_path, 'an_omniauth_provider_name', 'key=value').should + eq('/auth/an_omniauth_provider_name?key=value') + end + end +end diff --git a/spec/views/admin/sessions/new.html_spec.rb b/spec/views/admin/sessions/new.html_spec.rb index 7f9478a12..2c15e2b22 100644 --- a/spec/views/admin/sessions/new.html_spec.rb +++ b/spec/views/admin/sessions/new.html_spec.rb @@ -8,6 +8,7 @@ it "renders" do view.stub(:enki_config).and_return(Enki::Config.default) view.stub(:allow_login_bypass?).and_return(true) + view.stub(:auth_path).and_return('/auth/omniauth_path') render :template => '/admin/sessions/new', :formats => [:html] end end