bsm-sso-client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ require 'bsm/sso/client'
@@ -0,0 +1,57 @@
1
+ require 'rails'
2
+ require 'active_support/core_ext/numeric/time'
3
+ require 'active_support/dependencies'
4
+ require 'active_resource'
5
+ require 'action_controller'
6
+ require 'rails_warden'
7
+
8
+ module Bsm
9
+ module Sso
10
+ module Client
11
+ autoload :User, 'bsm/sso/client/user'
12
+ autoload :UserMethods, 'bsm/sso/client/user_methods'
13
+ autoload :UrlHelpers, 'bsm/sso/client/url_helpers'
14
+ autoload :FailureApp, 'bsm/sso/client/failure_app'
15
+
16
+ mattr_accessor :secret
17
+ @@secret = nil
18
+
19
+ mattr_accessor :expire_after
20
+ @@expire_after = 2.hours
21
+
22
+ mattr_writer :user_class
23
+ @@user_class = nil
24
+
25
+ class << self
26
+
27
+ delegate :site=, :site, :to => :"Bsm::Sso::Client::User"
28
+
29
+ def user_class
30
+ @@user_class || Bsm::Sso::Client::User
31
+ end
32
+
33
+ # Default message verifier
34
+ def verifier
35
+ raise "Please configure a secret! Example: Bsm::Sso::Client.secret = '...'" unless secret.present?
36
+ @verifier ||= ActiveSupport::MessageVerifier.new(secret)
37
+ end
38
+
39
+ # Configure the SSO. Example:
40
+ #
41
+ # # config/initializers/sso.rb
42
+ # Bsm::Sso::Client.configure do |c|
43
+ # c.site = "https://sso.example.com"
44
+ # c.secret = "m4GHRWxvXiL3ZSR8adShpqNWXmepkqeyUqRfpB8F"
45
+ # end
46
+ def configure(&block)
47
+ tap(&block)
48
+ end
49
+
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ require 'bsm/sso/client/railtie'
56
+ require 'bsm/sso/client/warden_ext'
57
+ require 'bsm/sso/client/strategies'
@@ -0,0 +1,41 @@
1
+ class Bsm::Sso::Client::FailureApp < ActionController::Metal
2
+ include ActionController::RackDelegation
3
+ include ActionController::Redirecting
4
+ include Bsm::Sso::Client::UrlHelpers
5
+
6
+ NAVIGATIONAL_FORMATS = [:html, :all, :js, nil].to_set.freeze
7
+ UnauthorizedAccess = Class.new(ActionController::ActionControllerError)
8
+
9
+ def self.call(env)
10
+ action(:respond).call(env)
11
+ end
12
+
13
+ def self.default_url_options(*args)
14
+ ApplicationController.default_url_options(*args)
15
+ end
16
+
17
+ def respond
18
+ if NAVIGATIONAL_FORMATS.include?(request.format.try(:to_sym))
19
+ request.xhr? ? respond_with_js! : redirect!
20
+ else
21
+ stop!
22
+ end
23
+ end
24
+
25
+ def redirect!
26
+ redirect_to Bsm::Sso::Client.user_class.sign_in_url(:service => service_url(env["warden.options"][:attempted_path])), :status => 303
27
+ end
28
+
29
+ def respond_with_js!
30
+ self.status = :ok
31
+ self.content_type = request.format.to_s
32
+ self.response_body = "alert('Your session has expired');"
33
+ end
34
+
35
+ # Throws UnauthorizedAccess (rescued as 403 Forbidden response)
36
+ def stop!(message = nil)
37
+ message ||= "You are not permitted to access the resource in #{request.path}"
38
+ raise UnauthorizedAccess, message
39
+ end
40
+
41
+ end
@@ -0,0 +1,31 @@
1
+ require 'bsm/sso/client'
2
+ require 'rails'
3
+
4
+ class Bsm::Sso::Client::Railtie < ::Rails::Railtie
5
+
6
+ initializer "bsm-sso.insert_middleware" do |app|
7
+ Bsm::Sso::Client::Railtie.insert_middleware!(app)
8
+ end
9
+
10
+ config.after_initialize do
11
+ Bsm::Sso::Client::Railtie.handle_exceptions!
12
+ end
13
+
14
+ def self.insert_middleware!(app)
15
+ app.config.middleware.use RailsWarden::Manager do |manager|
16
+ manager.default_strategies :sso_ticket, :sso_http_auth
17
+ manager.failure_app = Bsm::Sso::Client::FailureApp
18
+ end
19
+ end
20
+
21
+ def self.handle_exceptions!
22
+ return unless defined?(::ActionDispatch::ShowExceptions)
23
+ ActionDispatch::ShowExceptions.rescue_responses.update("Bsm::Sso::Client::FailureApp::UnauthorizedAccess" => :forbidden)
24
+ end
25
+
26
+ def self.plugin!(app)
27
+ insert_middleware!(app)
28
+ handle_exceptions!
29
+ end
30
+
31
+ end
@@ -0,0 +1,6 @@
1
+ module Bsm::Sso::Client::Strategies
2
+ end
3
+
4
+ require 'bsm/sso/client/strategies/base'
5
+ require 'bsm/sso/client/strategies/ticket'
6
+ require 'bsm/sso/client/strategies/http_auth'
@@ -0,0 +1,7 @@
1
+ class Bsm::Sso::Client::Strategies::Base < ::Warden::Strategies::Base
2
+
3
+ def user_class
4
+ Bsm::Sso::Client.user_class
5
+ end
6
+
7
+ end
@@ -0,0 +1,23 @@
1
+ class Bsm::Sso::Client::Strategies::HttpAuth < Bsm::Sso::Client::Strategies::Base
2
+
3
+ def store?
4
+ false
5
+ end
6
+
7
+ def valid?
8
+ token.present?
9
+ end
10
+
11
+ def authenticate!
12
+ u = user_class.authorize(token)
13
+ u.nil? ? fail!(:invalid) : success!(u)
14
+ end
15
+
16
+ def token
17
+ return nil unless request.authorization && request.authorization =~ /^Basic (.*)/m
18
+ @token ||= ActiveSupport::Base64.decode64($1).split(/:/, 2).first
19
+ end
20
+
21
+ Warden::Strategies.add :sso_http_auth, self
22
+
23
+ end
@@ -0,0 +1,14 @@
1
+ class Bsm::Sso::Client::Strategies::Ticket < Bsm::Sso::Client::Strategies::Base
2
+ include Bsm::Sso::Client::UrlHelpers
3
+
4
+ def valid?
5
+ params[:ticket].present?
6
+ end
7
+
8
+ def authenticate!
9
+ u = user_class.consume(params[:ticket], service_url)
10
+ u.nil? ? fail!(:invalid) : success!(u)
11
+ end
12
+
13
+ Warden::Strategies.add :sso_ticket, self
14
+ end
@@ -0,0 +1,12 @@
1
+ require 'active_support/core_ext/string/encoding'
2
+
3
+
4
+ module Bsm::Sso::Client::UrlHelpers
5
+
6
+ def service_url(path = request.fullpath)
7
+ part = Regexp.escape params.slice(:ticket).to_query
8
+ request.base_url + path.sub(/#{part}\&?/, '').chomp("&").chomp("?")
9
+ end
10
+
11
+ end
12
+
@@ -0,0 +1,45 @@
1
+ class Bsm::Sso::Client::User < ActiveResource::Base
2
+ self.format = :json
3
+
4
+ class << self
5
+
6
+ def headers
7
+ { 'AUTHORIZATION' => Bsm::Sso::Client.verifier.generate(30.seconds.from_now) }
8
+ end
9
+
10
+ def consume(ticket, service)
11
+ # TODO rename Sso endpoint to /validate
12
+ find :one, :from => '/validate', :params => { :ticket => ticket, :service => service }
13
+ rescue ActiveResource::ResourceInvalid
14
+ nil
15
+ end
16
+
17
+ def authorize(token)
18
+ find :one, :from => '/authorize', :params => { :auth_token => token }
19
+ rescue ActiveResource::ResourceInvalid
20
+ nil
21
+ end
22
+
23
+ def authenticate(credentials)
24
+ find :one, :from => "/authenticate", :params => credentials.slice(:email, :password)
25
+ rescue ActiveResource::ResourceInvalid
26
+ nil
27
+ end
28
+
29
+ def sign_in_url(params = {})
30
+ custom_absolute_method_root_url(:sign_in, params)
31
+ end
32
+
33
+ def sign_out_url(params = {})
34
+ custom_absolute_method_root_url(:sign_out, params)
35
+ end
36
+
37
+ private
38
+
39
+ def custom_absolute_method_root_url(method_name, params = {})
40
+ "#{site.to_s.chomp('/')}/#{method_name}#{query_string(params)}"
41
+ end
42
+
43
+ end
44
+ end
45
+
@@ -0,0 +1,29 @@
1
+ module Bsm::Sso::Client::UserMethods
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ class << self
6
+ delegate :sign_in_url, :sign_out_url, :to => :"Bsm::Sso::Client::User"
7
+ end
8
+ end
9
+
10
+ module ClassMethods
11
+
12
+ def consume(*a)
13
+ result = Bsm::Sso::Client::User.consume(*a)
14
+ new(result.attributes) if result
15
+ end
16
+
17
+ def authenticate(*a)
18
+ result = Bsm::Sso::Client::User.authenticate(*a)
19
+ new(result.attributes) if result
20
+ end
21
+
22
+ def authorize(*a)
23
+ result = Bsm::Sso::Client::User.authorize(*a)
24
+ new(result.attributes) if result
25
+ end
26
+
27
+ end
28
+ end
29
+
@@ -0,0 +1,11 @@
1
+ class Warden::SessionSerializer
2
+
3
+ def serialize(record)
4
+ record.id
5
+ end
6
+
7
+ def deserialize(id)
8
+ Bsm::Sso::Client.user_class.find(id)
9
+ end
10
+
11
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bsm-sso-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Dimitrij Denissenko
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-10-21 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activeresource
16
+ requirement: &25666220 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 3.0.0
22
+ - - <
23
+ - !ruby/object:Gem::Version
24
+ version: 3.2.0
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: *25666220
28
+ - !ruby/object:Gem::Dependency
29
+ name: actionpack
30
+ requirement: &25665200 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ! '>='
34
+ - !ruby/object:Gem::Version
35
+ version: 3.0.0
36
+ - - <
37
+ - !ruby/object:Gem::Version
38
+ version: 3.2.0
39
+ type: :runtime
40
+ prerelease: false
41
+ version_requirements: *25665200
42
+ - !ruby/object:Gem::Dependency
43
+ name: railties
44
+ requirement: &25663920 !ruby/object:Gem::Requirement
45
+ none: false
46
+ requirements:
47
+ - - ! '>='
48
+ - !ruby/object:Gem::Version
49
+ version: 3.0.0
50
+ - - <
51
+ - !ruby/object:Gem::Version
52
+ version: 3.2.0
53
+ type: :runtime
54
+ prerelease: false
55
+ version_requirements: *25663920
56
+ - !ruby/object:Gem::Dependency
57
+ name: rails_warden
58
+ requirement: &25662760 !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ~>
62
+ - !ruby/object:Gem::Version
63
+ version: 0.5.0
64
+ type: :runtime
65
+ prerelease: false
66
+ version_requirements: *25662760
67
+ - !ruby/object:Gem::Dependency
68
+ name: rake
69
+ requirement: &25648320 !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ! '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: *25648320
78
+ - !ruby/object:Gem::Dependency
79
+ name: rack-test
80
+ requirement: &25646620 !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: *25646620
89
+ - !ruby/object:Gem::Dependency
90
+ name: rspec
91
+ requirement: &25646200 !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ type: :development
98
+ prerelease: false
99
+ version_requirements: *25646200
100
+ - !ruby/object:Gem::Dependency
101
+ name: shoulda-matchers
102
+ requirement: &25645560 !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ! '>='
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ type: :development
109
+ prerelease: false
110
+ version_requirements: *25645560
111
+ - !ruby/object:Gem::Dependency
112
+ name: webmock
113
+ requirement: &25644920 !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: *25644920
122
+ description: ''
123
+ email: dimitrij@blacksquaremedia.com
124
+ executables: []
125
+ extensions: []
126
+ extra_rdoc_files: []
127
+ files:
128
+ - lib/bsm/sso/client.rb
129
+ - lib/bsm/sso/client/strategies/ticket.rb
130
+ - lib/bsm/sso/client/strategies/base.rb
131
+ - lib/bsm/sso/client/strategies/http_auth.rb
132
+ - lib/bsm/sso/client/failure_app.rb
133
+ - lib/bsm/sso/client/railtie.rb
134
+ - lib/bsm/sso/client/user_methods.rb
135
+ - lib/bsm/sso/client/url_helpers.rb
136
+ - lib/bsm/sso/client/user.rb
137
+ - lib/bsm/sso/client/warden_ext.rb
138
+ - lib/bsm/sso/client/strategies.rb
139
+ - lib/bsm-sso-client.rb
140
+ homepage: https://github.com/bsm/sso-client
141
+ licenses: []
142
+ post_install_message:
143
+ rdoc_options: []
144
+ require_paths:
145
+ - lib
146
+ required_ruby_version: !ruby/object:Gem::Requirement
147
+ none: false
148
+ requirements:
149
+ - - ! '>='
150
+ - !ruby/object:Gem::Version
151
+ version: 1.8.7
152
+ required_rubygems_version: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: 1.3.6
158
+ requirements: []
159
+ rubyforge_project:
160
+ rubygems_version: 1.8.10
161
+ signing_key:
162
+ specification_version: 3
163
+ summary: BSM's internal SSO client
164
+ test_files: []