Skip to content
This repository was archived by the owner on Jan 7, 2019. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ spec/dummy/db/development.sqlite3
spec/dummy/log/development.log
spec/dummy/log/test.log
spec/dummy/tmp
docs
57 changes: 57 additions & 0 deletions app/controllers/stormpath/rails/id_site_login/new_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
module Stormpath
module Rails
module IdSiteLogin
class NewController < BaseController
before_action :require_no_authentication!

def call
begin
result = Stormpath::Rails::Client.application.handle_id_site_callback(request.url)
account = Stormpath::Rails::Client.client.accounts.get(result.account_href)
login_the_account(account)
respond_with_success(account)
rescue Stormpath::Error, JWT::VerificationError => error
respond_with_error(error)
end
end

private

def login_the_account(account)
AccountLoginWithStormpathToken.new(
cookies, account,
Stormpath::Rails::Client.application,
Stormpath::Rails::Client.client.data_store.api_key
).call
end

def respond_with_success(account)
respond_to do |format|
format.html { redirect_to login_redirect_route, notice: 'Successfully signed in' }
format.json { render json: AccountSerializer.to_h(account) }
end
end

def respond_with_error(error)
respond_to do |format|
format.html do
flash.now[:error] = error.message
render stormpath_config.web.login.view
end
format.json do
render json: { message: error.message }, status: error.try(:status)
end
end
end

def login_redirect_route
if params[:next]
URI(params[:next]).path
else
stormpath_config.web.login.next_uri
end
end
end
end
end
end
19 changes: 19 additions & 0 deletions app/controllers/stormpath/rails/id_site_logout/new_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module Stormpath
module Rails
module IdSiteLogout
class NewController < BaseController
def call
TokenAndCookiesCleaner.new(cookies).remove
redirect_to callback_url
end

private

def callback_url
Stormpath::Rails::Client.application.create_id_site_url(callback_uri: root_url,
logout: true)
end
end
end
end
end
11 changes: 10 additions & 1 deletion app/controllers/stormpath/rails/login/new_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,23 @@ class NewController < BaseController

def call
if stormpath_config.web.id_site.enabled
redirect_to id_site_login_url
redirect_to callback_url
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would move to a seperate method

        private

        def callback_url
          Stormpath::Rails::Client.application.create_id_site_url(
            callback_uri: id_site_result_url,
            path: Stormpath::Rails.config.web.id_site.login_uri
          )
        end

else
respond_to do |format|
format.json { render json: LoginNewSerializer.to_h }
format.html { render stormpath_config.web.login.view }
end
end
end

private

def callback_url
Stormpath::Rails::Client.application.create_id_site_url(
callback_uri: id_site_result_url,
path: Stormpath::Rails.config.web.id_site.login_uri
)
end
end
end
end
Expand Down
21 changes: 1 addition & 20 deletions app/controllers/stormpath/rails/logout/create_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ def call
if bearer_authorization_header?
DeleteAccessToken.call(bearer_access_token)
else
delete_tokens
delete_cookies
TokenAndCookiesCleaner.new(cookies).remove
end
respond_with_success
end
Expand All @@ -28,24 +27,6 @@ def authorization_header
request.headers['Authorization']
end

def delete_tokens
DeleteAccessToken.call(cookies[access_token_cookie_name])
DeleteRefreshToken.call(cookies[refresh_token_cookie_name])
end

def delete_cookies
cookies.delete(access_token_cookie_name)
cookies.delete(refresh_token_cookie_name)
end

def access_token_cookie_name
stormpath_config.web.access_token_cookie.name
end

def refresh_token_cookie_name
stormpath_config.web.refresh_token_cookie.name
end

def respond_with_success
respond_to do |format|
format.html do
Expand Down
11 changes: 10 additions & 1 deletion app/controllers/stormpath/rails/register/new_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module Register
class NewController < BaseController
def call
if stormpath_config.web.id_site.enabled
redirect_to id_site_register_url
redirect_to callback_url
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would move to a seperate method

        private

        def callback_url
          Stormpath::Rails::Client.application.create_id_site_url(
            callback_uri: id_site_result_url,
            path: Stormpath::Rails.config.web.id_site.login_uri
          )
        end

elsif signed_in?
redirect_to root_path
else
Expand All @@ -14,6 +14,15 @@ def call
end
end
end

private

def callback_url
Stormpath::Rails::Client.application.create_id_site_url(
callback_uri: id_site_result_url,
path: Stormpath::Rails.config.web.id_site.register_uri
)
end
end
end
end
Expand Down
36 changes: 36 additions & 0 deletions app/services/stormpath/rails/token_and_cookies_cleaner.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
module Stormpath
module Rails
class TokenAndCookiesCleaner
attr_reader :cookies

def initialize(cookies)
@cookies = cookies
end

def remove
delete_tokens
delete_cookies
end

private

def delete_tokens
DeleteAccessToken.call(cookies[access_token_cookie_name])
DeleteRefreshToken.call(cookies[refresh_token_cookie_name])
end

def delete_cookies
cookies.delete(access_token_cookie_name)
cookies.delete(refresh_token_cookie_name)
end

def access_token_cookie_name
Stormpath::Rails.config.web.access_token_cookie.name
end

def refresh_token_cookie_name
Stormpath::Rails.config.web.refresh_token_cookie.name
end
end
end
end
Copy link
Contributor

@nikone nikone Oct 31, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 nice one :D

but it would be good to also have remove method covered with service specs

10 changes: 9 additions & 1 deletion lib/stormpath/rails/router.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ module Router
'oauth2#new' => 'stormpath/rails/oauth2/new#call',
'oauth2#create' => 'stormpath/rails/oauth2/create#call',
'verify_email#show' => 'stormpath/rails/verify_email/show#call',
'verify_email#create' => 'stormpath/rails/verify_email/create#call'
'verify_email#create' => 'stormpath/rails/verify_email/create#call',
'id_site_login#new' => 'stormpath/rails/id_site_login/new#call',
'id_site_logout#new' => 'stormpath/rails/id_site_logout/new#call'
}.freeze

def stormpath_rails_routes(actions: {})
Expand Down Expand Up @@ -66,6 +68,12 @@ def stormpath_rails_routes(actions: {})
get Stormpath::Rails.config.web.verify_email.uri => actions['verify_email#show'], as: :new_verify_email
post Stormpath::Rails.config.web.verify_email.uri => actions['verify_email#create'], as: :verify_email
end

# ID SITE LOGIN
if Stormpath::Rails.config.web.id_site.enabled
get '/id_site_result' => actions['id_site_login#new'], as: :id_site_result
get '/logout_id_site' => actions['id_site_logout#new'], as: :logout_id_site
end
end
end
end
Expand Down
5 changes: 5 additions & 0 deletions spec/dummy/app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
</head>
<body>

<% if signed_in? and Stormpath::Rails.config.web.id_site.enabled %>
<p>Logged in as: <%= current_account.given_name %></p>
<%= link_to "Log out", logout_id_site_path %>
<% end %>

<%= yield %>

</body>
Expand Down
2 changes: 1 addition & 1 deletion spec/factories.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FactoryGirl.define do
factory :account, class: Stormpath::Resource::Account do
sequence(:email) { |n| "dev#{n}@example.com" }
sequence(:email) { |n| "dev-#{n}-#{Faker::Lorem.word}@example.com" }
password 'Password1337'
given_name { Faker::Name.first_name }
surname { Faker::Name.last_name }
Expand Down
116 changes: 116 additions & 0 deletions spec/requests/id_site_login/get_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
require 'spec_helper'

describe 'IdSiteLogin GET', type: :request, vcr: true do
let(:application) { Stormpath::Rails::Client.application }
Timecop.freeze(Time.zone.now) do
let(:time) { Time.zone.now.to_i }
end
let(:cb_uri) { '/id_site_result' }
let(:path) { '' }
let(:tenant_name) { application.tenant.name }
let(:tenant_domain) { "https://#{tenant_name}.id.stormpath.io" }
let(:api_key_secret) { ENV['STORMPATH_API_KEY_SECRET'] }
let(:aud) { ENV['STORMPATH_API_KEY_ID'] }
let(:account) { application.accounts.create(account_attrs) }
let(:account_attrs) { FactoryGirl.attributes_for(:account) }
let(:jwt_response) do
JWT.encode(
{
'iss' => tenant_domain,
'sub' => account.href,
'aud' => aud,
'exp' => time + 1.minute.to_i,
'iat' => time,
'jti' => 'JX5HSMmEAevFBKJx4FfC3',
'irt' => '5fbb73e7-f81b-41f2-8031-b08750da6298',
'state' => '',
'isNewSub' => false,
'status' => 'AUTHENTICATED',
'cb_uri' => 'http://localhost:3000/id_site_result'
},
api_key_secret,
'HS256'
)
end

before do
allow(web_config.id_site).to receive(:enabled).and_return(true)
Rails.application.reload_routes!
end

after do
account.delete if account
allow(web_config.id_site).to receive(:enabled).and_return(false)
Rails.application.reload_routes!
end

describe 'HTTP_ACCEPT=text/html' do
context 'successfull login' do
it 'should redirect' do
get '/id_site_result', jwtResponse: jwt_response
expect(response).to redirect_to('/')
expect(response.status).to eq(302)
end
end

context 'invalid jwt' do
describe 'expired' do
let(:time) { Time.zone.now.to_i - 10.minutes }

it 'should render flash error' do
get '/id_site_result', jwtResponse: jwt_response
expect(controller).to set_flash[:error].now
end
end

describe 'bad signature' do
let(:api_key_secret) { 'badapikeysecret' }

it 'should render flash error' do
get '/id_site_result', jwtResponse: jwt_response
expect(controller).to set_flash[:error].now
end
end
end
end

describe 'application/json' do
let(:headers) do
{
'ACCEPT' => 'application/json'
}
end

context 'successfull login' do
it 'should respond with ok' do
get '/id_site_result', { jwtResponse: jwt_response }, headers
expect(response.status).to eq(200)
end

it 'should respond with the logged in account' do
get '/id_site_result', { jwtResponse: jwt_response }, headers
expect(response.body).to include('account')
end
end

context 'invalid jwt' do
describe 'expired' do
let(:time) { Time.zone.now.to_i - 10.minutes }

it 'should raise error' do
get '/id_site_result', { jwtResponse: jwt_response }, headers
expect(response.body).to include('message', 'Token is invalid')
end
end

describe 'bad signature' do
let(:api_key_secret) { 'badapikeysecret' }

it 'should render flash error' do
get '/id_site_result', { jwtResponse: jwt_response }, headers
expect(response.body).to include('message', 'Signature verification raised')
end
end
end
end
end
18 changes: 15 additions & 3 deletions spec/requests/login/get_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,21 @@ def json_login_get
xit 'login should show account stores' do
end

xit 'if id site enabled should redirect' do
json_login_get
expect(response.status).to eq(400)
describe 'if id site is enabled' do
before do
allow(web_config.id_site).to receive(:enabled).and_return(true)
Rails.application.reload_routes!
end

after do
allow(web_config.id_site).to receive(:enabled).and_return(false)
Rails.application.reload_routes!
end

it 'should redirect' do
json_login_get
expect(response.status).to eq(302)
end
end
end

Expand Down
Loading