doorkeeper_sso 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +13 -12
- data/app/controllers/application_controller.rb +3 -0
- data/app/controllers/doorkeeper/authorizations_controller.rb +18 -0
- data/app/controllers/doorkeeper/tokens_controller.rb +39 -0
- data/app/controllers/sso/sessions_controller.rb +29 -0
- data/app/middleware/sso/access_token_marker.rb +103 -0
- data/app/middleware/sso/authorization_grant_marker.rb +87 -0
- data/app/middleware/sso/passport_verification.rb +25 -0
- data/app/models/sso/session.rb +137 -0
- data/app/views/layouts/doorkeeper/admin.html.erb +34 -0
- data/app/views/layouts/doorkeeper/application.html.erb +23 -0
- data/config/routes.rb +1 -0
- data/db/migrate/20150414102248_create_sso_sessions.rb +29 -0
- data/lib/doorkeeper_sso.rb +4 -1
- data/lib/sso/engine.rb +0 -12
- data/lib/sso/logging.rb +58 -0
- data/lib/sso/version.rb +1 -1
- data/lib/sso.rb +4 -0
- data/spec/controllers/sso/sessions_controller_spec.rb +65 -0
- data/spec/fabricators/api_application_fabricator.rb +16 -0
- data/spec/fabricators/doorkeeper_access_grant_fabricator.rb +4 -0
- data/spec/fabricators/doorkeeper_access_token_fabricator.rb +5 -0
- data/spec/fabricators/doorkeeper_application_fabricator.rb +5 -0
- data/spec/fabricators/sso_session_fabricator.rb +6 -0
- data/spec/fabricators/user_fabricator.rb +35 -0
- data/spec/models/sso/session_spec.rb +183 -0
- data/spec/rails_helper.rb +21 -6
- data/spec/support/devise.rb +28 -0
- data/spec/test_app/Rakefile +0 -4
- data/spec/test_app/app/models/user.rb +39 -0
- data/spec/test_app/config/database.yml +5 -20
- data/spec/test_app/config/initializers/devise.rb +259 -0
- data/spec/test_app/config/initializers/doorkeeper.rb +111 -0
- data/spec/test_app/config/routes.rb +5 -1
- data/spec/test_app/db/schema.rb +78 -0
- metadata +86 -67
- data/app/controllers/sso/application_controller.rb +0 -4
- data/spec/test_app/README.rdoc +0 -28
- data/spec/test_app/app/assets/javascripts/application.js +0 -13
- data/spec/test_app/app/assets/stylesheets/application.css +0 -15
- data/spec/test_app/app/controllers/application_controller.rb +0 -5
- data/spec/test_app/app/helpers/application_helper.rb +0 -2
- data/spec/test_app/app/views/layouts/application.html.erb +0 -14
- data/spec/test_app/bin/bundle +0 -3
- data/spec/test_app/bin/rails +0 -4
- data/spec/test_app/bin/rake +0 -4
- data/spec/test_app/bin/setup +0 -29
- data/spec/test_app/config/application.rb +0 -32
- data/spec/test_app/config/boot.rb +0 -5
- data/spec/test_app/config/environment.rb +0 -5
- data/spec/test_app/config/environments/development.rb +0 -41
- data/spec/test_app/config/environments/production.rb +0 -79
- data/spec/test_app/config/environments/test.rb +0 -42
- data/spec/test_app/config/initializers/assets.rb +0 -11
- data/spec/test_app/config/initializers/backtrace_silencers.rb +0 -7
- data/spec/test_app/config/initializers/cookies_serializer.rb +0 -3
- data/spec/test_app/config/initializers/filter_parameter_logging.rb +0 -4
- data/spec/test_app/config/initializers/inflections.rb +0 -16
- data/spec/test_app/config/initializers/mime_types.rb +0 -4
- data/spec/test_app/config/initializers/session_store.rb +0 -3
- data/spec/test_app/config/initializers/wrap_parameters.rb +0 -14
- data/spec/test_app/config/locales/en.yml +0 -23
- data/spec/test_app/config/secrets.yml +0 -22
- data/spec/test_app/config.ru +0 -4
- data/spec/test_app/public/404.html +0 -67
- data/spec/test_app/public/422.html +0 -67
- data/spec/test_app/public/500.html +0 -66
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1325cddaeea3ad9c0db0f7421de65c7d671f4e90
|
4
|
+
data.tar.gz: f0c5fe37e55ee02487802801fda7c05ff6a9e679
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 35345790590a3d6a0a534ae30dd7717793ef3cf12036f6baf0780ebb03c014ec51110aa97574ed7ff7e299eacfb82afa4dca32fb4e772dd8131a48655788221b
|
7
|
+
data.tar.gz: 0da08dc94ecc077d572615e0dbf0ff0194529cd4dc5a57f23be4b4fb7d835e7352ab40f74acc61abd9fe0151e27d2591472049b19331aa6f8b067d47897491b6
|
data/Rakefile
CHANGED
@@ -1,26 +1,27 @@
|
|
1
|
+
#!/usr/bin/env rake
|
1
2
|
begin
|
2
3
|
require 'bundler/setup'
|
3
4
|
rescue LoadError
|
4
5
|
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
6
|
end
|
7
|
+
Bundler.require :default, :test
|
6
8
|
|
7
|
-
require '
|
8
|
-
|
9
|
-
|
10
|
-
rdoc.rdoc_dir = 'rdoc'
|
11
|
-
rdoc.title = 'Sso'
|
12
|
-
rdoc.options << '--line-numbers'
|
13
|
-
rdoc.rdoc_files.include('README.rdoc')
|
14
|
-
rdoc.rdoc_files.include('lib/**/*.rb')
|
9
|
+
require 'rake'
|
10
|
+
task :environment do
|
11
|
+
Combustion.initialize!
|
15
12
|
end
|
13
|
+
Combustion::Application.load_tasks
|
16
14
|
|
17
15
|
APP_RAKEFILE = File.expand_path("../spec/test_app/Rakefile", __FILE__)
|
18
16
|
load 'rails/tasks/engine.rake'
|
17
|
+
require "rspec/core/rake_task"
|
19
18
|
|
19
|
+
Bundler::GemHelper.install_tasks
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
task :default => :spec
|
24
22
|
|
25
|
-
|
23
|
+
# RSpec::Core::RakeTask.new(:spec) do |spec|
|
24
|
+
# spec.pattern = 'spec/**/*_spec.rb'
|
25
|
+
# # spec.rspec_opts = ['-cfs --backtrace']
|
26
|
+
# end
|
26
27
|
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Doorkeeper
|
2
|
+
class AuthorizationsController < Doorkeeper::ApplicationController
|
3
|
+
|
4
|
+
after_action :after_grant_create, only: [:new, :create]
|
5
|
+
|
6
|
+
protected
|
7
|
+
|
8
|
+
def after_grant_create
|
9
|
+
Rails.logger.info "AuthorizationsController#Create : after_action"
|
10
|
+
code_response = authorization.instance_variable_get("@response")
|
11
|
+
if code_response
|
12
|
+
warden_session = session["warden.user.user.session"]
|
13
|
+
Rails.logger.debug "Sso::Session.update_master_with_grant - #{warden_session["sso_session_id"].inspect}, #{code_response.auth.token.inspect}"
|
14
|
+
Sso::Session.update_master_with_grant(warden_session["sso_session_id"], code_response.auth.token)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Doorkeeper
|
2
|
+
class TokensController < Doorkeeper::ApplicationMetalController
|
3
|
+
include AbstractController::Callbacks
|
4
|
+
|
5
|
+
after_action :after_token_create, only: :create
|
6
|
+
|
7
|
+
protected
|
8
|
+
|
9
|
+
def after_token_create
|
10
|
+
Rails.logger.info "TokensController#Create : after_action"
|
11
|
+
handle_authorization_grant_flow
|
12
|
+
end
|
13
|
+
|
14
|
+
def handle_authorization_grant_flow
|
15
|
+
# We cannot rely on session[:sso_session_id] here because the end-user might have cookies disabled.
|
16
|
+
# The only thing we can rely on to identify the user/Passport is the incoming grant token.
|
17
|
+
Rails.logger.debug { %(Detected outgoing "Access Token" #{outgoing_access_token.inspect}) }
|
18
|
+
if sso_session = Sso::Session.update_master_with_access_token(grant_token, outgoing_access_token)
|
19
|
+
Rails.logger.debug "::Sso::Session.register_access_token success for access_token: #{outgoing_access_token}"
|
20
|
+
else
|
21
|
+
Rails.logger.debug "::Sso::Session.register_access_token failed. #{sso_session.errors.inspect}"
|
22
|
+
warden.logout
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def grant_token
|
27
|
+
params["code"]
|
28
|
+
end
|
29
|
+
|
30
|
+
def grant_type
|
31
|
+
params["grant_type"]
|
32
|
+
end
|
33
|
+
|
34
|
+
def outgoing_access_token
|
35
|
+
@response_hash ||= JSON.parse(response.body)
|
36
|
+
@response_hash["access_token"]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Sso::SessionsController < ApplicationController
|
2
|
+
|
3
|
+
before_action :authenticate_user!, only: :show
|
4
|
+
before_action :doorkeeper_authorize!, only: :create
|
5
|
+
before_action :find_user, only: :create
|
6
|
+
|
7
|
+
# TODO: Security issue?
|
8
|
+
protect_from_forgery with: :null_session
|
9
|
+
|
10
|
+
respond_to :json
|
11
|
+
|
12
|
+
# Returns a 200 if access is granted
|
13
|
+
def show
|
14
|
+
render :nothing => true
|
15
|
+
end
|
16
|
+
|
17
|
+
# Generate an SSO:Session
|
18
|
+
def create
|
19
|
+
@session = Sso::Session.generate(@user, doorkeeper_token, params )
|
20
|
+
respond_with @session, :location => sso.sessions_url
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def find_user
|
26
|
+
@user = User.find(doorkeeper_token.resource_owner_id)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# app/middleware/sso/access_token_marker.rb
|
2
|
+
# Middleware that catches outgoing Doorkeeper access tokens
|
3
|
+
|
4
|
+
module Sso
|
5
|
+
class AccessTokenMarker
|
6
|
+
|
7
|
+
def initialize(app)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
@env = env
|
13
|
+
@request = ::ActionDispatch::Request.new @env
|
14
|
+
@response = @app.call @env
|
15
|
+
|
16
|
+
return response unless request.method == 'POST'
|
17
|
+
return response unless authorization_grant_flow? || password_credential_flow?
|
18
|
+
return response unless response_code == 200
|
19
|
+
return response unless response_body
|
20
|
+
return response unless outgoing_access_token
|
21
|
+
|
22
|
+
if authorization_grant_flow?
|
23
|
+
Rails.logger.debug { %{Detected outgoing "Access Token" #{outgoing_access_token.inspect} of the "Authorization Code Grant" flow (belonging to "Authorization Grant Token" #{grant_token.inspect}). Augmenting related Passport with it.} }
|
24
|
+
registration = ::Passports.register_access_token grant_token: grant_token, access_token: outgoing_access_token
|
25
|
+
|
26
|
+
if registration.failure?
|
27
|
+
Rails.logger.warn { "The passport could not be augmented. Destroying warden session." }
|
28
|
+
warden.logout
|
29
|
+
end
|
30
|
+
|
31
|
+
elsif password_credential_flow?
|
32
|
+
Rails.logger.debug { %{Detected outgoing "Access Token" #{outgoing_access_token.inspect} of the "Resource Owner Password Credentials Grant" flow. Generating new Passport with it.} }
|
33
|
+
generation = ::Passports.generate_with_access_token access_token_string: outgoing_access_token, ip: request.ip, agent: request.user_agent
|
34
|
+
|
35
|
+
if generation.failure?
|
36
|
+
Rails.logger.warn { "The passport could not be generated. Destroying warden session." }
|
37
|
+
warden.logout
|
38
|
+
end
|
39
|
+
|
40
|
+
else
|
41
|
+
fail NotImplementedError
|
42
|
+
end
|
43
|
+
|
44
|
+
response
|
45
|
+
end
|
46
|
+
|
47
|
+
def request
|
48
|
+
@request
|
49
|
+
end
|
50
|
+
|
51
|
+
def response
|
52
|
+
@response
|
53
|
+
end
|
54
|
+
|
55
|
+
def response_body
|
56
|
+
response.last.first.presence
|
57
|
+
# raise response.last.inspect
|
58
|
+
end
|
59
|
+
|
60
|
+
def response_code
|
61
|
+
response.first
|
62
|
+
end
|
63
|
+
|
64
|
+
def parsed_response_body
|
65
|
+
# raise response_body.inspect
|
66
|
+
return unless response_body
|
67
|
+
::JSON.parse response_body
|
68
|
+
rescue JSON::ParserError => exception
|
69
|
+
Trouble.notify exception
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def outgoing_access_token
|
74
|
+
return unless parsed_response_body
|
75
|
+
parsed_response_body['access_token']
|
76
|
+
end
|
77
|
+
|
78
|
+
def warden
|
79
|
+
request.env['warden']
|
80
|
+
end
|
81
|
+
|
82
|
+
def params
|
83
|
+
request.params
|
84
|
+
end
|
85
|
+
|
86
|
+
def authorization_grant_flow?
|
87
|
+
grant_token.present?
|
88
|
+
end
|
89
|
+
|
90
|
+
def password_credential_flow?
|
91
|
+
grant_type == 'password'
|
92
|
+
end
|
93
|
+
|
94
|
+
def grant_token
|
95
|
+
params['code']
|
96
|
+
end
|
97
|
+
|
98
|
+
def grant_type
|
99
|
+
params['grant_type']
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# app/middleware/sso/authorization_grant_maker.rb
|
2
|
+
# Middleware that catches outgoing Doorkeeper authorization grants
|
3
|
+
|
4
|
+
module Sso
|
5
|
+
class AuthorizationGrantMarker
|
6
|
+
|
7
|
+
def initialize(app)
|
8
|
+
@app = app
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(env)
|
12
|
+
@env = env
|
13
|
+
@response = @app.call @env
|
14
|
+
|
15
|
+
return response unless outgoing_grant_token
|
16
|
+
|
17
|
+
if passport_id
|
18
|
+
Rails.logger.debug { %{Detected outgoing "Authorization Grant Token" #{outgoing_grant_token.inspect} of the "Authorization Code Grant" flow. Augmenting Passport #{passport_id.inspect} with it.} }
|
19
|
+
registration = ::Passports.register_authorization_grant passport_id: passport_id, token: outgoing_grant_token
|
20
|
+
|
21
|
+
if registration.failure?
|
22
|
+
Rails.logger.warn { "The passport could not be augmented. Destroying warden session." }
|
23
|
+
warden.logout
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
response
|
28
|
+
end
|
29
|
+
|
30
|
+
def request
|
31
|
+
::ActionDispatch::Request.new @env
|
32
|
+
end
|
33
|
+
|
34
|
+
def response
|
35
|
+
@response
|
36
|
+
end
|
37
|
+
|
38
|
+
def code
|
39
|
+
response.first
|
40
|
+
end
|
41
|
+
|
42
|
+
def session
|
43
|
+
request.session
|
44
|
+
end
|
45
|
+
|
46
|
+
def warden
|
47
|
+
request.env['warden']
|
48
|
+
end
|
49
|
+
|
50
|
+
def passport_id
|
51
|
+
session['passport_id']
|
52
|
+
end
|
53
|
+
|
54
|
+
def location_header
|
55
|
+
unless code == 302
|
56
|
+
#logger.debug { "Uninteresting response, because it is not a redirect" }
|
57
|
+
return
|
58
|
+
end
|
59
|
+
|
60
|
+
response.second['Location']
|
61
|
+
end
|
62
|
+
|
63
|
+
def redirect_uri
|
64
|
+
unless location_header
|
65
|
+
#logger.debug { "Uninteresting response, because there is no Location header" }
|
66
|
+
return
|
67
|
+
end
|
68
|
+
|
69
|
+
::URI.parse location_header
|
70
|
+
end
|
71
|
+
|
72
|
+
def redirect_uri_params
|
73
|
+
return unless redirect_uri
|
74
|
+
::Rack::Utils.parse_query redirect_uri.query
|
75
|
+
end
|
76
|
+
|
77
|
+
def outgoing_grant_token
|
78
|
+
unless redirect_uri_params && redirect_uri_params['code']
|
79
|
+
#logger.debug { "Uninteresting response, because there is no code parameter sent" }
|
80
|
+
return
|
81
|
+
end
|
82
|
+
|
83
|
+
redirect_uri_params['code']
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# app/middleware/sso/passport_verification.rb
|
2
|
+
# A Middleware to verify incoming requests by client applications
|
3
|
+
# which would like to verify the passport a user presented to them
|
4
|
+
|
5
|
+
module Sso
|
6
|
+
class PassportVerification
|
7
|
+
|
8
|
+
def initialize(app)
|
9
|
+
@app = app
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
request = Rack::Request.new(env)
|
14
|
+
|
15
|
+
if request.path == '/api/v1/passports/verify'
|
16
|
+
logger.debug { "Detected Passport verification request." }
|
17
|
+
env['warden'].authenticate! :passport
|
18
|
+
else
|
19
|
+
# logger.debug { "I'm not interested in this request to #{request.path}" }
|
20
|
+
@app.call(env)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
module Sso
|
2
|
+
class Session < ActiveRecord::Base
|
3
|
+
include ::Sso::Logging
|
4
|
+
# FIXME: Not sure to use application or doorkeeper_application_id
|
5
|
+
belongs_to :application, class_name: 'Doorkeeper::Application' #, inverse_of: :sso_sessions
|
6
|
+
belongs_to :access_grant, class_name: 'Doorkeeper::AccessGrant' #, inverse_of: :sso_sessions
|
7
|
+
belongs_to :access_token, class_name: 'Doorkeeper::AccessToken' #, inverse_of: :sso_sessions
|
8
|
+
belongs_to :owner, class_name: 'User' #, inverse_of: :sso_sessions
|
9
|
+
|
10
|
+
validates :group_id, presence: true
|
11
|
+
validates :owner_id, presence: true
|
12
|
+
validates :ip, presence: true
|
13
|
+
validates :secret, presence: true
|
14
|
+
validates :access_token_id, uniqueness: { scope: [:owner_id, :revoked_at, :application_id], allow_blank: true }
|
15
|
+
validates :revoke_reason, allow_blank: true, format: { with: /\A[a-z_]+\z/ }
|
16
|
+
|
17
|
+
scope :active, -> { where(revoked_at: nil) }
|
18
|
+
scope :master, -> { where(application_id: nil) }
|
19
|
+
|
20
|
+
before_validation :ensure_secret
|
21
|
+
before_validation :ensure_group_id
|
22
|
+
before_validation :ensure_activity_at
|
23
|
+
|
24
|
+
class << self
|
25
|
+
def master_for(grant_id)
|
26
|
+
active.master.find_by!(access_grant_id: grant_id)
|
27
|
+
end
|
28
|
+
|
29
|
+
def generate_master(user, options)
|
30
|
+
relations = { owner: user }
|
31
|
+
attributes = ActionController::Parameters.new(options).permit(:ip, :agent, :location)
|
32
|
+
debug { "Sso::Session::generate_master for #{user.inspect} - #{attributes.inspect}" }
|
33
|
+
create!(relations.merge(attributes))
|
34
|
+
end
|
35
|
+
|
36
|
+
def generate(user, access_token, options = {})
|
37
|
+
master_sso_session = active.master.find_by!(owner_id: user.id, access_token_id: access_token.id)
|
38
|
+
attributes = ActionController::Parameters.new(options).permit(:ip, :agent, :location)
|
39
|
+
relations = { owner: user, application: access_token.application, access_token: access_token, group_id: master_sso_session.group_id }
|
40
|
+
|
41
|
+
debug { "Sso::Session::generate for #{user.inspect} - #{access_token.inspect} - #{attributes.inspect}" }
|
42
|
+
create!(relations.merge(attributes))
|
43
|
+
end
|
44
|
+
|
45
|
+
def logout(sso_session_id)
|
46
|
+
sso_session = find(sso_session_id)
|
47
|
+
group_id = sso_session.group_id
|
48
|
+
|
49
|
+
debug { "Sso::Session#logout - Revoking Session Group #{sso_session.group_id.inspect} from Session #{sso_session.id.inspect}" }
|
50
|
+
count = where(group_id: group_id).update_all revoked_at: Time.current, revoke_reason: "logout"
|
51
|
+
debug { "Successfully removed #{count.inspect} sessions." }
|
52
|
+
count
|
53
|
+
end
|
54
|
+
|
55
|
+
def update_master_with_grant(master_sso_session_id, oauth_grant)
|
56
|
+
master_sso_session = active.master.find(master_sso_session_id)
|
57
|
+
|
58
|
+
if master_sso_session.update_attribute(:access_grant_id, oauth_grant.id)
|
59
|
+
debug { "#update_master_with_grant : #{master_sso_session.id} with Access Grant ID #{oauth_grant.id} which is #{oauth_grant.token}" }
|
60
|
+
else
|
61
|
+
error { "#update_master_with_grant : FAILED to update oauth_grant" }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def update_master_with_access_token(grant_token, access_token)
|
66
|
+
oauth_grant = Doorkeeper::AccessGrant.by_token(grant_token)
|
67
|
+
oauth_token = Doorkeeper::AccessToken.by_token(access_token)
|
68
|
+
return false if oauth_token.blank? or oauth_grant.blank?
|
69
|
+
|
70
|
+
master_sso_session = active.master.find_by!(access_grant_id: oauth_grant.id)
|
71
|
+
|
72
|
+
if master_sso_session.update_attribute(:access_token_id, oauth_token.id)
|
73
|
+
debug { "#register_access_token : #{master_sso_session.id} with Access Token ID #{oauth_token.id} which is #{oauth_token.token}" }
|
74
|
+
else
|
75
|
+
error { "#register_access_token : FAILED to update oauth_access_token_id" }
|
76
|
+
end
|
77
|
+
master_sso_session
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def create_session(token, options = {})
|
82
|
+
create(access_token_id)
|
83
|
+
end
|
84
|
+
# def to_s
|
85
|
+
# ['Sso:Session', owner_id, ip, activity_at].join ', '
|
86
|
+
# end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def ensure_secret
|
91
|
+
self.secret ||= SecureRandom.uuid
|
92
|
+
end
|
93
|
+
|
94
|
+
def ensure_group_id
|
95
|
+
self.group_id ||= SecureRandom.uuid
|
96
|
+
end
|
97
|
+
|
98
|
+
def ensure_activity_at
|
99
|
+
self.activity_at ||= Time.current
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end # Sso
|
103
|
+
|
104
|
+
|
105
|
+
# == Schema Information
|
106
|
+
# Schema version: 20150330031153
|
107
|
+
#
|
108
|
+
# Table name: sso_sessions
|
109
|
+
#
|
110
|
+
# id :uuid not null, primary key
|
111
|
+
# access_grant_id :integer
|
112
|
+
# access_token_id :integer
|
113
|
+
# application_id :integer
|
114
|
+
# owner_id :integer not null
|
115
|
+
# group_id :string not null
|
116
|
+
# secret :string not null
|
117
|
+
# ip :inet not null
|
118
|
+
# agent :string
|
119
|
+
# location :string
|
120
|
+
# activity_at :datetime not null
|
121
|
+
# revoked_at :datetime
|
122
|
+
# revoke_reason :string
|
123
|
+
# created_at :datetime not null
|
124
|
+
# updated_at :datetime not null
|
125
|
+
#
|
126
|
+
# Indexes
|
127
|
+
#
|
128
|
+
# index_sso_sessions_on_access_grant_id (access_grant_id)
|
129
|
+
# index_sso_sessions_on_access_token_id (access_token_id)
|
130
|
+
# index_sso_sessions_on_application_id (application_id)
|
131
|
+
# index_sso_sessions_on_group_id (group_id)
|
132
|
+
# index_sso_sessions_on_ip (ip)
|
133
|
+
# index_sso_sessions_on_owner_id (owner_id)
|
134
|
+
# index_sso_sessions_on_revoke_reason (revoke_reason)
|
135
|
+
# index_sso_sessions_on_secret (secret)
|
136
|
+
# one_access_token_per_owner (owner_id,access_token_id,application_id) UNIQUE
|
137
|
+
#
|
@@ -0,0 +1,34 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
7
|
+
<title>Doorkeeper</title>
|
8
|
+
<%= stylesheet_link_tag "doorkeeper/admin/application" %>
|
9
|
+
<%= csrf_meta_tags %>
|
10
|
+
</head>
|
11
|
+
<body>
|
12
|
+
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
13
|
+
<div class="container">
|
14
|
+
<div class="navbar-header">
|
15
|
+
<%= link_to t('doorkeeper.layouts.admin.nav.oauth2_provider'), oauth_applications_path, class: 'navbar-brand' %>
|
16
|
+
</div>
|
17
|
+
<ul class="nav navbar-nav">
|
18
|
+
<%= content_tag :li, class: "#{'active' if request.path == oauth_applications_path}" do %>
|
19
|
+
<%= link_to t('doorkeeper.layouts.admin.nav.applications'), oauth_applications_path %>
|
20
|
+
<% end %>
|
21
|
+
</ul>
|
22
|
+
</div>
|
23
|
+
</div>
|
24
|
+
<div class="container">
|
25
|
+
<%- if flash[:notice].present? %>
|
26
|
+
<div class="alert alert-info">
|
27
|
+
<%= flash[:notice] %>
|
28
|
+
</div>
|
29
|
+
<% end -%>
|
30
|
+
|
31
|
+
<%= yield %>
|
32
|
+
</div>
|
33
|
+
</body>
|
34
|
+
</html>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title><%= t('doorkeeper.layouts.application.title') %></title>
|
5
|
+
<meta charset="utf-8">
|
6
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
8
|
+
|
9
|
+
<%= stylesheet_link_tag "doorkeeper/application" %>
|
10
|
+
<%= csrf_meta_tags %>
|
11
|
+
</head>
|
12
|
+
<body>
|
13
|
+
<div id="container">
|
14
|
+
<%- if flash[:notice].present? %>
|
15
|
+
<div class="alert alert-info">
|
16
|
+
<%= flash[:notice] %>
|
17
|
+
</div>
|
18
|
+
<% end -%>
|
19
|
+
|
20
|
+
<%= yield %>
|
21
|
+
</div>
|
22
|
+
</body>
|
23
|
+
</html>
|
data/config/routes.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
1
|
+
class CreateSsoSessions < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
enable_extension 'uuid-ossp'
|
4
|
+
|
5
|
+
create_table :sso_sessions, id: :uuid do |t|
|
6
|
+
t.references "access_grant", index: true
|
7
|
+
t.references "access_token", index: true
|
8
|
+
t.references "application", index: true
|
9
|
+
t.integer "owner_id", null: false
|
10
|
+
t.string "group_id", null: false
|
11
|
+
t.string "secret", null: false
|
12
|
+
t.inet "ip", null: false
|
13
|
+
t.string "agent"
|
14
|
+
t.string "location"
|
15
|
+
t.datetime "activity_at", null: false
|
16
|
+
t.datetime "revoked_at"
|
17
|
+
t.string "revoke_reason"
|
18
|
+
t.timestamps
|
19
|
+
end
|
20
|
+
|
21
|
+
add_index :sso_sessions, [:owner_id, :access_token_id, :application_id], where: 'revoked_at IS NULL AND access_token_id IS NOT NULL', unique: true, name: :one_access_token_per_owner
|
22
|
+
add_index :sso_sessions, :owner_id
|
23
|
+
add_index :sso_sessions, :group_id
|
24
|
+
add_index :sso_sessions, :secret
|
25
|
+
add_index :sso_sessions, :ip
|
26
|
+
add_index :sso_sessions, :revoke_reason
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
data/lib/doorkeeper_sso.rb
CHANGED
data/lib/sso/engine.rb
CHANGED
@@ -1,17 +1,5 @@
|
|
1
1
|
module Sso
|
2
2
|
class Engine < ::Rails::Engine
|
3
3
|
isolate_namespace Sso
|
4
|
-
|
5
|
-
# Generators for Rspec and Fabrication
|
6
|
-
config.generators do |g|
|
7
|
-
g.test_framework :rspec,
|
8
|
-
:fixtures => true,
|
9
|
-
:view_specs => false,
|
10
|
-
:helper_specs => false,
|
11
|
-
:routing_specs => false,
|
12
|
-
:controller_specs => true,
|
13
|
-
:request_specs => false
|
14
|
-
g.fixture_replacement :fabrication
|
15
|
-
end
|
16
4
|
end
|
17
5
|
end
|
data/lib/sso/logging.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
module Sso
|
2
|
+
# One thing tha bugs me is when I cannot see which part of the code caused a log message.
|
3
|
+
# This mixin will include the current class name as Logger `progname` so you can show that it in your logfiles.
|
4
|
+
#
|
5
|
+
module Logging
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
class_methods do
|
9
|
+
def debug(&block)
|
10
|
+
logger && logger.debug(progname, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def info(&block)
|
14
|
+
logger && logger.info(progname, &block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def warn(&block)
|
18
|
+
logger && logger.warn(progname, &block)
|
19
|
+
end
|
20
|
+
|
21
|
+
def error(&block)
|
22
|
+
logger && logger.error(progname, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def fatal(&block)
|
26
|
+
logger && logger.fatal(progname, &block)
|
27
|
+
end
|
28
|
+
|
29
|
+
def progname
|
30
|
+
self.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
def logger
|
34
|
+
Rails.logger
|
35
|
+
end
|
36
|
+
end #class_methods
|
37
|
+
|
38
|
+
def debug(&block)
|
39
|
+
self.class.debug(&block)
|
40
|
+
end
|
41
|
+
|
42
|
+
def info(&block)
|
43
|
+
self.class.info(&block)
|
44
|
+
end
|
45
|
+
|
46
|
+
def warn(&block)
|
47
|
+
self.class.warn(&block)
|
48
|
+
end
|
49
|
+
|
50
|
+
def error(&block)
|
51
|
+
self.class.error(&block)
|
52
|
+
end
|
53
|
+
|
54
|
+
def fatal(&block)
|
55
|
+
self.class.fatal(&block)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/sso/version.rb
CHANGED