discourse/spec/controllers/session_controller_spec.rb
Sam 6f31d3f0e5 FEATURE: single sign on support
Added support for outsourcing auth to a different website, documentation on meta
2014-02-25 14:31:03 +11:00

305 lines
8.6 KiB
Ruby

require 'spec_helper'
describe SessionController do
describe '.sso_login' do
before do
@sso_url = "http://somesite.com/discourse_sso"
@sso_secret = "shjkfdhsfkjh"
SiteSetting.stubs("enable_sso").returns(true)
SiteSetting.stubs("sso_url").returns(@sso_url)
SiteSetting.stubs("sso_secret").returns(@sso_secret)
end
def get_sso
nonce = SecureRandom.hex
dso = DiscourseSingleSignOn.new
dso.nonce = nonce
dso.register_nonce
sso = SingleSignOn.new
sso.nonce = nonce
sso.sso_secret = @sso_secret
sso
end
it 'can take over an account' do
sso = get_sso
user = Fabricate(:user)
sso.email = user.email
sso.external_id = "abc"
get :sso_login, Rack::Utils.parse_query(sso.payload)
response.should redirect_to('/')
logged_on_user = Discourse.current_user_provider.new(request.env).current_user
logged_on_user.email.should == user.email
logged_on_user.single_sign_on_record.external_id.should == "abc"
end
it 'allows you to create an account' do
sso = get_sso
sso.external_id = '666' # the number of the beast
sso.email = 'bob@bob.com'
sso.name = 'Sam Saffron'
sso.username = 'sam'
get :sso_login, Rack::Utils.parse_query(sso.payload)
response.should redirect_to('/')
logged_on_user = Discourse.current_user_provider.new(request.env).current_user
logged_on_user.email.should == 'bob@bob.com'
logged_on_user.name.should == 'Sam Saffron'
logged_on_user.username.should == 'sam'
logged_on_user.single_sign_on_record.external_id.should == "666"
end
it 'allows login to existing account with valid nonce' do
sso = get_sso
sso.external_id = '997'
sso.return_url = '/hello/world'
user = Fabricate(:user)
user.create_single_sign_on_record(external_id: '997', last_payload: '')
get :sso_login, Rack::Utils.parse_query(sso.payload)
user.single_sign_on_record.reload
user.single_sign_on_record.last_payload.should == sso.unsigned_payload
response.should redirect_to('/hello/world')
logged_on_user = Discourse.current_user_provider.new(request.env).current_user
user.id.should == logged_on_user.id
# nonce is bad now
get :sso_login, Rack::Utils.parse_query(sso.payload)
response.code.should == '500'
end
end
describe '.create' do
let(:user) { Fabricate(:user) }
context 'when email is confirmed' do
before do
token = user.email_tokens.where(email: user.email).first
EmailToken.confirm(token.token)
end
it "raises an error when the login isn't present" do
lambda { xhr :post, :create }.should raise_error(ActionController::ParameterMissing)
end
describe 'invalid password' do
it "should return an error with an invalid password" do
xhr :post, :create, login: user.username, password: 'sssss'
::JSON.parse(response.body)['error'].should be_present
end
end
describe 'suspended user' do
it 'should return an error' do
User.any_instance.stubs(:suspended?).returns(true)
User.any_instance.stubs(:suspended_till).returns(2.days.from_now)
xhr :post, :create, login: user.username, password: 'myawesomepassword'
::JSON.parse(response.body)['error'].should be_present
end
end
describe 'success by username' do
before do
xhr :post, :create, login: user.username, password: 'myawesomepassword'
user.reload
end
it 'sets a session id' do
session[:current_user_id].should == user.id
end
it 'gives the user an auth token' do
user.auth_token.should be_present
end
it 'sets a cookie with the auth token' do
cookies[:_t].should == user.auth_token
end
end
describe 'strips leading @ symbol' do
before do
xhr :post, :create, login: "@" + user.username, password: 'myawesomepassword'
user.reload
end
it 'sets a session id' do
session[:current_user_id].should == user.id
end
end
describe 'also allow login by email' do
before do
xhr :post, :create, login: user.email, password: 'myawesomepassword'
end
it 'sets a session id' do
session[:current_user_id].should == user.id
end
end
context 'login has leading and trailing space' do
let(:username) { " #{user.username} " }
let(:email) { " #{user.email} " }
it "strips spaces from the username" do
xhr :post, :create, login: username, password: 'myawesomepassword'
::JSON.parse(response.body)['error'].should_not be_present
end
it "strips spaces from the email" do
xhr :post, :create, login: email, password: 'myawesomepassword'
::JSON.parse(response.body)['error'].should_not be_present
end
end
describe "when the site requires approval of users" do
before do
SiteSetting.expects(:must_approve_users?).returns(true)
end
context 'with an unapproved user' do
before do
xhr :post, :create, login: user.email, password: 'myawesomepassword'
end
it "doesn't log in the user" do
session[:current_user_id].should be_blank
end
it "shows the 'not approved' error message" do
expect(JSON.parse(response.body)['error']).to eq(
I18n.t('login.not_approved')
)
end
end
context "with an unapproved user who is an admin" do
before do
User.any_instance.stubs(:admin?).returns(true)
xhr :post, :create, login: user.email, password: 'myawesomepassword'
end
it 'sets a session id' do
session[:current_user_id].should == user.id
end
end
end
end
context 'when email has not been confirmed' do
def post_login
xhr :post, :create, login: user.email, password: 'myawesomepassword'
end
it "doesn't log in the user" do
post_login
session[:current_user_id].should be_blank
end
it "shows the 'not activated' error message" do
post_login
expect(JSON.parse(response.body)['error']).to eq(
I18n.t 'login.not_activated'
)
end
context "and the 'must approve users' site setting is enabled" do
before { SiteSetting.expects(:must_approve_users?).returns(true) }
it "shows the 'not approved' error message" do
post_login
expect(JSON.parse(response.body)['error']).to eq(
I18n.t 'login.not_approved'
)
end
end
end
end
describe '.destroy' do
before do
@user = log_in
xhr :delete, :destroy, id: @user.username
end
it 'removes the session variable' do
session[:current_user_id].should be_blank
end
it 'removes the auth token cookie' do
cookies[:_t].should be_blank
end
end
describe '.forgot_password' do
it 'raises an error without a username parameter' do
lambda { xhr :post, :forgot_password }.should raise_error(ActionController::ParameterMissing)
end
context 'for a non existant username' do
it "doesn't generate a new token for a made up username" do
lambda { xhr :post, :forgot_password, login: 'made_up'}.should_not change(EmailToken, :count)
end
it "doesn't enqueue an email" do
Jobs.expects(:enqueue).with(:user_mail, anything).never
xhr :post, :forgot_password, login: 'made_up'
end
end
context 'for an existing username' do
let(:user) { Fabricate(:user) }
it "generates a new token for a made up username" do
lambda { xhr :post, :forgot_password, login: user.username}.should change(EmailToken, :count)
end
it "enqueues an email" do
Jobs.expects(:enqueue).with(:user_email, has_entries(type: :forgot_password, user_id: user.id))
xhr :post, :forgot_password, login: user.username
end
end
end
describe '.current' do
context "when not logged in" do
it "retuns 404" do
xhr :get, :current
response.should_not be_success
end
end
context "when logged in" do
let!(:user) { log_in }
it "returns the JSON for the user" do
xhr :get, :current
response.should be_success
json = ::JSON.parse(response.body)
json['current_user'].should be_present
json['current_user']['id'].should == user.id
end
end
end
end