sso 0.0.2 → 0.1.0.alpha1

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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/lib/sso.rb +6 -0
  3. data/spec/dummy/Rakefile +9 -0
  4. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  5. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  6. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  7. data/spec/dummy/app/controllers/home_controller.rb +4 -0
  8. data/spec/dummy/app/controllers/sessions_controller.rb +39 -0
  9. data/spec/dummy/app/models/user.rb +9 -0
  10. data/spec/dummy/app/views/home/index.html.erb +0 -0
  11. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  12. data/spec/dummy/app/views/sessions/new.html.erb +10 -0
  13. data/spec/dummy/bin/bundle +3 -0
  14. data/spec/dummy/bin/rails +4 -0
  15. data/spec/dummy/bin/rake +4 -0
  16. data/spec/dummy/bin/setup +29 -0
  17. data/spec/dummy/config.ru +4 -0
  18. data/spec/dummy/config/application.rb +36 -0
  19. data/spec/dummy/config/boot.rb +4 -0
  20. data/spec/dummy/config/database.yml +38 -0
  21. data/spec/dummy/config/environment.rb +5 -0
  22. data/spec/dummy/config/environments/development.rb +37 -0
  23. data/spec/dummy/config/environments/test.rb +42 -0
  24. data/spec/dummy/config/initializers/assets.rb +11 -0
  25. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  26. data/spec/dummy/config/initializers/doorkeeper.rb +23 -0
  27. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  28. data/spec/dummy/config/initializers/secret_token.rb +10 -0
  29. data/spec/dummy/config/initializers/session_store.rb +3 -0
  30. data/spec/dummy/config/initializers/sso.rb +37 -0
  31. data/spec/dummy/config/initializers/warden.rb +29 -0
  32. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  33. data/spec/dummy/config/locales/doorkeeper.en.yml +151 -0
  34. data/spec/dummy/config/locales/en.yml +23 -0
  35. data/spec/dummy/config/routes.rb +12 -0
  36. data/spec/dummy/db/migrate/20150302113121_add_users.rb +14 -0
  37. data/spec/dummy/db/migrate/20150303054803_create_doorkeeper_tables.rb +51 -0
  38. data/spec/dummy/db/migrate/20150303132931_create_passports_table.rb +38 -0
  39. data/spec/dummy/db/schema.rb +97 -0
  40. data/spec/integration/oauth/after_fetch_spec.rb +43 -0
  41. data/spec/integration/oauth/authorization_code_spec.rb +56 -0
  42. data/spec/integration/oauth/password_verification_spec.rb +67 -0
  43. data/spec/lib/sso/logging_spec.rb +39 -0
  44. data/spec/spec_helper.rb +54 -0
  45. data/spec/support/factories/doorkeeper/application.rb +21 -0
  46. data/spec/support/factories/server/passport.rb +10 -0
  47. data/spec/support/factories/server/user.rb +14 -0
  48. data/spec/support/sso/test.rb +9 -0
  49. data/spec/support/sso/test/cookie_stripper.rb +20 -0
  50. data/spec/support/sso/test/helpers.rb +56 -0
  51. metadata +283 -17
@@ -0,0 +1,3 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ Rails.application.config.session_store :cookie_store, key: '_dummy_session'
@@ -0,0 +1,37 @@
1
+ # POI
2
+
3
+ # This is the minimal configuration you need to do for using the sso gem.
4
+
5
+ SSO.configure do |config|
6
+
7
+ config.find_user_for_passport = proc do |passport, ip|
8
+ # This is your chance to modify the user instance before it is handed out to the OAuth client apps.
9
+
10
+ progname = 'SSO.config.find_user_for_passport'
11
+ Rails.logger.debug(progname) { "Looking up User #{passport.owner_id} belonging to Passport #{passport.id} surfing with IP #{ip}..." }
12
+ user = User.find_by_id passport.owner_id
13
+ return unless user
14
+
15
+ # The IP address, for example, might be used to set certain flags on the user object.
16
+ # If these flags are included in the #user_state base (see below), all OAuth client apps are immediately aware of the change.
17
+ if ip == '198.51.100.74'
18
+ user.tags << :is_at_the_office
19
+ else
20
+ user.tags << :is_working_from_home
21
+ end
22
+
23
+ user
24
+ end
25
+
26
+ config.user_state_base = proc do |user|
27
+ # Include the end-user credentials to force all OAuth client apps to refetch the end-user Passports.
28
+ # This way you can revoke all relevant Passports on SSO-logout and the OAuth client apps are immediately aware of it.
29
+ [user.email, user.password, user.tags.sort].join
30
+ end
31
+
32
+ # This is a rather static key used to calculate whether a user state changed and needs to be propagated to the OAuth clients.
33
+ # It's not a problem if this changes, as long as it's somewhat deterministic.
34
+ # In our case, we simply derive it from the Rails secret_key_base so we don't have to remember yet another secret somewhere.
35
+ generator = ActiveSupport::KeyGenerator.new Rails.application.config.secret_key_base, iterations: 1000
36
+ config.user_state_key = Rails.application.config.user_state_digest_key = generator.generate_key 'user state digest key'
37
+ end
@@ -0,0 +1,29 @@
1
+ # POI
2
+ ::Warden::Strategies.add :password do
3
+ def valid?
4
+ params['username'].present?
5
+ end
6
+
7
+ def authenticate!
8
+ Rails.logger.debug(progname) { 'Authenticating from username and password...' }
9
+
10
+ user = ::User.authenticate params['username'], params['password']
11
+
12
+ if user
13
+ Rails.logger.debug(progname) { 'Authentication from username and password successful.' }
14
+ success! user
15
+ else
16
+ Rails.logger.debug(progname) { 'Authentication from username and password failed.' }
17
+ fail! 'Could not login.'
18
+ end
19
+ end
20
+
21
+ def progname
22
+ 'Warden::Strategies.password'
23
+ end
24
+ end
25
+
26
+ # POI
27
+ Warden::Manager.after_authentication(&::SSO::Server::Warden::Hooks::AfterAuthentication.to_proc)
28
+ Warden::Manager.before_logout(&::SSO::Server::Warden::Hooks::BeforeLogout.to_proc)
29
+ Warden::Strategies.add :passport, ::SSO::Server::Warden::Strategies::Passport
@@ -0,0 +1,14 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # This file contains settings for ActionController::ParamsWrapper which
4
+ # is enabled by default.
5
+
6
+ # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
7
+ ActiveSupport.on_load(:action_controller) do
8
+ wrap_parameters format: [:json] if respond_to?(:wrap_parameters)
9
+ end
10
+
11
+ # To enable root element in JSON for ActiveRecord objects.
12
+ # ActiveSupport.on_load(:active_record) do
13
+ # self.include_root_in_json = true
14
+ # end
@@ -0,0 +1,151 @@
1
+ en:
2
+ activerecord:
3
+ attributes:
4
+ doorkeeper/application:
5
+ name: 'Name'
6
+ redirect_uri: 'Redirect URI'
7
+ errors:
8
+ models:
9
+ doorkeeper/application:
10
+ attributes:
11
+ redirect_uri:
12
+ fragment_present: 'cannot contain a fragment.'
13
+ invalid_uri: 'must be a valid URI.'
14
+ relative_uri: 'must be an absolute URI.'
15
+ secured_uri: 'must be an HTTPS/SSL URI.'
16
+
17
+ mongoid:
18
+ attributes:
19
+ doorkeeper/application:
20
+ name: 'Name'
21
+ redirect_uri: 'Redirect URI'
22
+ errors:
23
+ models:
24
+ doorkeeper/application:
25
+ attributes:
26
+ redirect_uri:
27
+ fragment_present: 'cannot contain a fragment.'
28
+ invalid_uri: 'must be a valid URI.'
29
+ relative_uri: 'must be an absolute URI.'
30
+ secured_uri: 'must be an HTTPS/SSL URI.'
31
+
32
+ mongo_mapper:
33
+ attributes:
34
+ doorkeeper/application:
35
+ name: 'Name'
36
+ redirect_uri: 'Redirect URI'
37
+ errors:
38
+ models:
39
+ doorkeeper/application:
40
+ attributes:
41
+ redirect_uri:
42
+ fragment_present: 'cannot contain a fragment.'
43
+ invalid_uri: 'must be a valid URI.'
44
+ relative_uri: 'must be an absolute URI.'
45
+ secured_uri: 'must be an HTTPS/SSL URI.'
46
+
47
+ doorkeeper:
48
+ applications:
49
+ confirmations:
50
+ destroy: 'Are you sure?'
51
+ buttons:
52
+ edit: 'Edit'
53
+ destroy: 'Destroy'
54
+ submit: 'Submit'
55
+ cancel: 'Cancel'
56
+ authorize: 'Authorize'
57
+ form:
58
+ error: 'Whoops! Check your form for possible errors'
59
+ help:
60
+ redirect_uri: 'Use one line per URI'
61
+ native_redirect_uri: 'Use %{native_redirect_uri} for local tests'
62
+ edit:
63
+ title: 'Edit application'
64
+ index:
65
+ title: 'Your applications'
66
+ new: 'New Application'
67
+ name: 'Name'
68
+ callback_url: 'Callback URL'
69
+ new:
70
+ title: 'New Application'
71
+ show:
72
+ title: 'Application: %{name}'
73
+ application_id: 'Application Id'
74
+ secret: 'Secret'
75
+ callback_urls: 'Callback urls'
76
+ actions: 'Actions'
77
+
78
+ authorizations:
79
+ buttons:
80
+ authorize: 'Authorize'
81
+ deny: 'Deny'
82
+ error:
83
+ title: 'An error has occurred'
84
+ new:
85
+ title: 'Authorize required'
86
+ prompt: 'Authorize %{client_name} to use your account?'
87
+ able_to: 'This application will be able to'
88
+ show:
89
+ title: 'Authorization code'
90
+
91
+ authorized_applications:
92
+ confirmations:
93
+ revoke: 'Are you sure?'
94
+ buttons:
95
+ revoke: 'Revoke'
96
+ index:
97
+ title: 'Your authorized applications'
98
+ application: 'Application'
99
+ created_at: 'Created At'
100
+ date_format: '%Y-%m-%d %H:%M:%S'
101
+
102
+ errors:
103
+ messages:
104
+ # Common error messages
105
+ invalid_request: 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.'
106
+ invalid_redirect_uri: 'The redirect uri included is not valid.'
107
+ unauthorized_client: 'The client is not authorized to perform this request using this method.'
108
+ access_denied: 'The resource owner or authorization server denied the request.'
109
+ invalid_scope: 'The requested scope is invalid, unknown, or malformed.'
110
+ server_error: 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.'
111
+ temporarily_unavailable: 'The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.'
112
+
113
+ #configuration error messages
114
+ credential_flow_not_configured: 'Resource Owner Password Credentials flow failed due to Doorkeeper.configure.resource_owner_from_credentials being unconfigured.'
115
+ resource_owner_authenticator_not_configured: 'Resource Owner find failed due to Doorkeeper.configure.resource_owner_authenticator being unconfiged.'
116
+
117
+ # Access grant errors
118
+ unsupported_response_type: 'The authorization server does not support this response type.'
119
+
120
+ # Access token errors
121
+ invalid_client: 'Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method.'
122
+ invalid_grant: 'The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.'
123
+ unsupported_grant_type: 'The authorization grant type is not supported by the authorization server.'
124
+
125
+ # Password Access token errors
126
+ invalid_resource_owner: 'The provided resource owner credentials are not valid, or resource owner cannot be found'
127
+
128
+ invalid_token:
129
+ revoked: "The access token was revoked"
130
+ expired: "The access token expired"
131
+ unknown: "The access token is invalid"
132
+
133
+ flash:
134
+ applications:
135
+ create:
136
+ notice: 'Application created.'
137
+ destroy:
138
+ notice: 'Application deleted.'
139
+ update:
140
+ notice: 'Application updated.'
141
+ authorized_applications:
142
+ destroy:
143
+ notice: 'Application revoked.'
144
+
145
+ layouts:
146
+ admin:
147
+ nav:
148
+ oauth2_provider: 'OAuth2 Provider'
149
+ applications: 'Applications'
150
+ application:
151
+ title: 'OAuth authorize required'
@@ -0,0 +1,23 @@
1
+ # Files in the config/locales directory are used for internationalization
2
+ # and are automatically loaded by Rails. If you want to use locales other
3
+ # than English, add the necessary files in this directory.
4
+ #
5
+ # To use the locales, use `I18n.t`:
6
+ #
7
+ # I18n.t 'hello'
8
+ #
9
+ # In views, this is aliased to just `t`:
10
+ #
11
+ # <%= t('hello') %>
12
+ #
13
+ # To use a different locale, set it with `I18n.locale`:
14
+ #
15
+ # I18n.locale = :es
16
+ #
17
+ # This would use the information in config/locales/es.yml.
18
+ #
19
+ # To learn more, please read the Rails Internationalization guide
20
+ # available at http://guides.rubyonrails.org/i18n.html.
21
+
22
+ en:
23
+ hello: "Hello world"
@@ -0,0 +1,12 @@
1
+ Rails.application.routes.draw do
2
+
3
+ use_doorkeeper do
4
+ skip_controllers :applications, :authorized_applications
5
+ end
6
+
7
+ resources :sessions, only: [:new, :create]
8
+ get '/logout(/:passport_id)', to: 'sessions#logout', as: :logout
9
+
10
+ root to: 'home#index'
11
+
12
+ end
@@ -0,0 +1,14 @@
1
+ # This is not part of SSO, this is simply an example implementation of a user model.
2
+
3
+ class AddUsers < ActiveRecord::Migration
4
+ def change
5
+ create_table :users do |t|
6
+ t.string :name, null: false
7
+ t.string :email, null: false
8
+ t.string :password, null: false # <- Of course you would have this encrypted in a real-life setup
9
+ t.string :tags, array: true, default: []
10
+ t.boolean :vip
11
+ t.timestamps null: false
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,51 @@
1
+ # POI
2
+
3
+ # This migration file is created when you run `rails generate doorkeeper:install` in your OAuth Server Rails app.
4
+ # These tables are needed for Doorkeeper to work, see also https://github.com/doorkeeper-gem/doorkeeper#installation
5
+ # This migration here has *not* been modified. You simply see the original file below, created by the Doorkeeper generator.
6
+
7
+ # Note, however, that it was generated with Doorkeeper >= 2.0.0, since it has the `scopes` column on the `oauth_applications` table.
8
+ # We make use of that column and it was introduced here: https://github.com/doorkeeper-gem/doorkeeper/blob/master/CHANGELOG.md#200
9
+
10
+ class CreateDoorkeeperTables < ActiveRecord::Migration
11
+ def change
12
+ create_table :oauth_applications do |t|
13
+ t.string :name, null: false
14
+ t.string :uid, null: false
15
+ t.string :secret, null: false
16
+ t.text :redirect_uri, null: false
17
+ t.string :scopes, null: false, default: '' # <- Exists only with Doorkeeper 2.0.0 or higher.
18
+ t.timestamps null: false
19
+ end
20
+
21
+ add_index :oauth_applications, :uid, unique: true
22
+
23
+ create_table :oauth_access_grants do |t|
24
+ t.integer :resource_owner_id, null: false
25
+ t.integer :application_id, null: false
26
+ t.string :token, null: false
27
+ t.integer :expires_in, null: false
28
+ t.text :redirect_uri, null: false
29
+ t.datetime :created_at, null: false
30
+ t.datetime :revoked_at
31
+ t.string :scopes
32
+ end
33
+
34
+ add_index :oauth_access_grants, :token, unique: true
35
+
36
+ create_table :oauth_access_tokens do |t|
37
+ t.integer :resource_owner_id
38
+ t.integer :application_id
39
+ t.string :token, null: false
40
+ t.string :refresh_token
41
+ t.integer :expires_in
42
+ t.datetime :revoked_at
43
+ t.datetime :created_at, null: false
44
+ t.string :scopes
45
+ end
46
+
47
+ add_index :oauth_access_tokens, :token, unique: true
48
+ add_index :oauth_access_tokens, :resource_owner_id
49
+ add_index :oauth_access_tokens, :refresh_token, unique: true
50
+ end
51
+ end
@@ -0,0 +1,38 @@
1
+ # POI
2
+
3
+ # This is what the Passport table on the SSO Server looks like. You need to have this migration.
4
+ # As you can see it uses the `uuid` and `inet` column types. So you are kind of stuck with Postgres.
5
+ # However, there should be no reason for you not to simply use `integer` and `string` for those two columns instead.
6
+
7
+ class CreatePassportsTable < ActiveRecord::Migration
8
+ def change
9
+ enable_extension 'uuid-ossp'
10
+
11
+ create_table :passports, id: :uuid do |t|
12
+ t.integer :oauth_access_grant_id
13
+ t.integer :oauth_access_token_id
14
+ t.integer :application_id, null: false
15
+ t.integer :owner_id, null: false
16
+ t.string :group_id, null: false
17
+ t.string :secret, null: false, unique: true
18
+ t.inet :ip, null: false
19
+ t.string :agent
20
+ t.string :location
21
+ t.datetime :activity_at, null: false
22
+ t.datetime :revoked_at
23
+ t.string :revoke_reason
24
+ t.timestamps null: false
25
+ end
26
+
27
+ add_index :passports, [:owner_id, :oauth_access_token_id], where: 'revoked_at IS NULL AND oauth_access_token_id IS NOT NULL', unique: true, name: :one_access_token_per_owner
28
+
29
+ add_index :passports, :oauth_access_grant_id
30
+ add_index :passports, :oauth_access_token_id
31
+ add_index :passports, :application_id
32
+ add_index :passports, :owner_id
33
+ add_index :passports, :group_id
34
+ add_index :passports, :secret
35
+ add_index :passports, :ip
36
+ add_index :passports, :revoke_reason
37
+ end
38
+ end
@@ -0,0 +1,97 @@
1
+ # encoding: UTF-8
2
+ # This file is auto-generated from the current state of the database. Instead
3
+ # of editing this file, please use the migrations feature of Active Record to
4
+ # incrementally modify your database, and then regenerate this schema definition.
5
+ #
6
+ # Note that this schema.rb definition is the authoritative source for your
7
+ # database schema. If you need to create the application database on another
8
+ # system, you should be using db:schema:load, not running all the migrations
9
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
11
+ #
12
+ # It's strongly recommended that you check this file into your version control system.
13
+
14
+ ActiveRecord::Schema.define(version: 20150303132931) do
15
+
16
+ # These are extensions that must be enabled in order to support this database
17
+ enable_extension "plpgsql"
18
+ enable_extension "uuid-ossp"
19
+
20
+ create_table "oauth_access_grants", force: :cascade do |t|
21
+ t.integer "resource_owner_id", null: false
22
+ t.integer "application_id", null: false
23
+ t.string "token", null: false
24
+ t.integer "expires_in", null: false
25
+ t.text "redirect_uri", null: false
26
+ t.datetime "created_at", null: false
27
+ t.datetime "revoked_at"
28
+ t.string "scopes"
29
+ end
30
+
31
+ add_index "oauth_access_grants", ["token"], name: "index_oauth_access_grants_on_token", unique: true, using: :btree
32
+
33
+ create_table "oauth_access_tokens", force: :cascade do |t|
34
+ t.integer "resource_owner_id"
35
+ t.integer "application_id"
36
+ t.string "token", null: false
37
+ t.string "refresh_token"
38
+ t.integer "expires_in"
39
+ t.datetime "revoked_at"
40
+ t.datetime "created_at", null: false
41
+ t.string "scopes"
42
+ end
43
+
44
+ add_index "oauth_access_tokens", ["refresh_token"], name: "index_oauth_access_tokens_on_refresh_token", unique: true, using: :btree
45
+ add_index "oauth_access_tokens", ["resource_owner_id"], name: "index_oauth_access_tokens_on_resource_owner_id", using: :btree
46
+ add_index "oauth_access_tokens", ["token"], name: "index_oauth_access_tokens_on_token", unique: true, using: :btree
47
+
48
+ create_table "oauth_applications", force: :cascade do |t|
49
+ t.string "name", null: false
50
+ t.string "uid", null: false
51
+ t.string "secret", null: false
52
+ t.text "redirect_uri", null: false
53
+ t.string "scopes", default: "", null: false
54
+ t.datetime "created_at", null: false
55
+ t.datetime "updated_at", null: false
56
+ end
57
+
58
+ add_index "oauth_applications", ["uid"], name: "index_oauth_applications_on_uid", unique: true, using: :btree
59
+
60
+ create_table "passports", id: :uuid, default: "uuid_generate_v4()", force: :cascade do |t|
61
+ t.integer "oauth_access_grant_id"
62
+ t.integer "oauth_access_token_id"
63
+ t.integer "application_id", null: false
64
+ t.integer "owner_id", null: false
65
+ t.string "group_id", null: false
66
+ t.string "secret", null: false
67
+ t.inet "ip", null: false
68
+ t.string "agent"
69
+ t.string "location"
70
+ t.datetime "activity_at", null: false
71
+ t.datetime "revoked_at"
72
+ t.string "revoke_reason"
73
+ t.datetime "created_at", null: false
74
+ t.datetime "updated_at", null: false
75
+ end
76
+
77
+ add_index "passports", ["application_id"], name: "index_passports_on_application_id", using: :btree
78
+ add_index "passports", ["group_id"], name: "index_passports_on_group_id", using: :btree
79
+ add_index "passports", ["ip"], name: "index_passports_on_ip", using: :btree
80
+ add_index "passports", ["oauth_access_grant_id"], name: "index_passports_on_oauth_access_grant_id", using: :btree
81
+ add_index "passports", ["oauth_access_token_id"], name: "index_passports_on_oauth_access_token_id", using: :btree
82
+ add_index "passports", ["owner_id", "oauth_access_token_id"], name: "one_access_token_per_owner", unique: true, where: "((revoked_at IS NULL) AND (oauth_access_token_id IS NOT NULL))", using: :btree
83
+ add_index "passports", ["owner_id"], name: "index_passports_on_owner_id", using: :btree
84
+ add_index "passports", ["revoke_reason"], name: "index_passports_on_revoke_reason", using: :btree
85
+ add_index "passports", ["secret"], name: "index_passports_on_secret", using: :btree
86
+
87
+ create_table "users", force: :cascade do |t|
88
+ t.string "name", null: false
89
+ t.string "email", null: false
90
+ t.string "password", null: false
91
+ t.string "tags", default: [], array: true
92
+ t.boolean "vip"
93
+ t.datetime "created_at", null: false
94
+ t.datetime "updated_at", null: false
95
+ end
96
+
97
+ end