doorkeeper_sso 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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