osso 0.0.3.7
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 +7 -0
- data/.buildkite/hooks/environment +9 -0
- data/.buildkite/hooks/pre-command +7 -0
- data/.buildkite/pipeline.yml +6 -0
- data/.buildkite/template.yml +5 -0
- data/.gitignore +10 -0
- data/.rspec +1 -0
- data/.rubocop.yml +81 -0
- data/CODE_OF_CONDUCT.md +130 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +176 -0
- data/LICENSE +111 -0
- data/README.md +2 -0
- data/Rakefile +14 -0
- data/bin/console +8 -0
- data/bin/setup +8 -0
- data/config/database.yml +14 -0
- data/db/schema.rb +133 -0
- data/lib/osso.rb +11 -0
- data/lib/osso/Rakefile +13 -0
- data/lib/osso/db/migrate/20190909230109_enable_uuid.rb +7 -0
- data/lib/osso/db/migrate/20200328135750_create_users.rb +12 -0
- data/lib/osso/db/migrate/20200328143303_create_oauth_tables.rb +57 -0
- data/lib/osso/db/migrate/20200328143305_create_identity_providers.rb +12 -0
- data/lib/osso/db/migrate/20200411184535_add_provider_id_to_users.rb +7 -0
- data/lib/osso/db/migrate/20200411192645_create_enterprise_accounts.rb +15 -0
- data/lib/osso/db/migrate/20200413132407_add_oauth_clients.rb +13 -0
- data/lib/osso/db/migrate/20200413142511_create_authorization_codes.rb +15 -0
- data/lib/osso/db/migrate/20200413163451_create_access_tokens.rb +13 -0
- data/lib/osso/db/migrate/20200502120616_create_redirect_uris_and_drop_from_oauth_clients.rb +13 -0
- data/lib/osso/db/migrate/20200502135008_add_oauth_client_id_to_enterprise_accounts_and_identity_providers.rb +6 -0
- data/lib/osso/db/migrate/20200714223226_add_identity_provider_service_enum.rb +17 -0
- data/lib/osso/db/migrate/20200715154211_rename_idp_fields_on_identity_provider_to_sso.rb +6 -0
- data/lib/osso/db/migrate/20200715205801_add_name_to_enterprise_account.rb +5 -0
- data/lib/osso/graphql/mutation.rb +16 -0
- data/lib/osso/graphql/mutations.rb +12 -0
- data/lib/osso/graphql/mutations/base_mutation.rb +41 -0
- data/lib/osso/graphql/mutations/configure_identity_provider.rb +36 -0
- data/lib/osso/graphql/mutations/create_enterprise_account.rb +25 -0
- data/lib/osso/graphql/mutations/create_identity_provider.rb +30 -0
- data/lib/osso/graphql/mutations/set_identity_provider.rb +27 -0
- data/lib/osso/graphql/query.rb +25 -0
- data/lib/osso/graphql/resolvers.rb +12 -0
- data/lib/osso/graphql/resolvers/enterprise_account.rb +25 -0
- data/lib/osso/graphql/resolvers/enterprise_accounts.rb +17 -0
- data/lib/osso/graphql/resolvers/oauth_clients.rb +15 -0
- data/lib/osso/graphql/schema.rb +46 -0
- data/lib/osso/graphql/types.rb +15 -0
- data/lib/osso/graphql/types/base_enum.rb +10 -0
- data/lib/osso/graphql/types/base_input_object.rb +10 -0
- data/lib/osso/graphql/types/base_object.rb +12 -0
- data/lib/osso/graphql/types/enterprise_account.rb +33 -0
- data/lib/osso/graphql/types/identity_provider.rb +37 -0
- data/lib/osso/graphql/types/identity_provider_service.rb +12 -0
- data/lib/osso/graphql/types/oauth_client.rb +20 -0
- data/lib/osso/graphql/types/user.rb +17 -0
- data/lib/osso/helpers/auth.rb +71 -0
- data/lib/osso/helpers/helpers.rb +8 -0
- data/lib/osso/lib/app_config.rb +20 -0
- data/lib/osso/lib/oauth2_token.rb +38 -0
- data/lib/osso/lib/route_map.rb +28 -0
- data/lib/osso/models/access_token.rb +29 -0
- data/lib/osso/models/authorization_code.rb +14 -0
- data/lib/osso/models/enterprise_account.rb +28 -0
- data/lib/osso/models/identity_provider.rb +48 -0
- data/lib/osso/models/models.rb +16 -0
- data/lib/osso/models/oauth_client.rb +32 -0
- data/lib/osso/models/redirect_uri.rb +20 -0
- data/lib/osso/models/saml_provider.rb +49 -0
- data/lib/osso/models/saml_providers/azure_saml_provider.rb +22 -0
- data/lib/osso/models/saml_providers/okta_saml_provider.rb +23 -0
- data/lib/osso/models/user.rb +24 -0
- data/lib/osso/rake.rb +4 -0
- data/lib/osso/routes/admin.rb +41 -0
- data/lib/osso/routes/auth.rb +67 -0
- data/lib/osso/routes/oauth.rb +63 -0
- data/lib/osso/routes/routes.rb +10 -0
- data/lib/osso/routes/views/error.erb +1 -0
- data/lib/osso/routes/views/multiple_providers.erb +1 -0
- data/lib/osso/version.rb +5 -0
- data/lib/tasks/bootstrap.rake +16 -0
- data/osso-rb.gemspec +40 -0
- data/spec/factories/authorization_code.rb +10 -0
- data/spec/factories/enterprise_account.rb +46 -0
- data/spec/factories/identity_providers.rb +49 -0
- data/spec/factories/oauth_client.rb +12 -0
- data/spec/factories/redirect_uri.rb +14 -0
- data/spec/factories/user.rb +18 -0
- data/spec/graphql/mutations/configure_identity_provider_spec.rb +75 -0
- data/spec/graphql/mutations/create_enterprise_account_spec.rb +68 -0
- data/spec/graphql/mutations/create_identity_provider_spec.rb +104 -0
- data/spec/graphql/query/enterprise_account_spec.rb +68 -0
- data/spec/graphql/query/enterprise_accounts_spec.rb +44 -0
- data/spec/graphql/query/identity_provider_spec.rb +65 -0
- data/spec/graphql/query/oauth_clients_account_spec.rb +48 -0
- data/spec/models/azure_saml_provider_spec.rb +19 -0
- data/spec/models/identity_provider_spec.rb +17 -0
- data/spec/models/okta_saml_provider_spec.rb +20 -0
- data/spec/routes/admin_spec.rb +60 -0
- data/spec/routes/app_spec.rb +6 -0
- data/spec/routes/auth_spec.rb +112 -0
- data/spec/routes/oauth_spec.rb +134 -0
- data/spec/spec_helper.rb +68 -0
- data/spec/support/spec_app.rb +9 -0
- data/spec/support/views/admin.erb +5 -0
- metadata +348 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Osso
|
|
4
|
+
module Types
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
require_relative 'types/base_object'
|
|
9
|
+
require_relative 'types/base_enum'
|
|
10
|
+
require_relative 'types/base_input_object'
|
|
11
|
+
require_relative 'types/identity_provider_service'
|
|
12
|
+
require_relative 'types/identity_provider'
|
|
13
|
+
require_relative 'types/enterprise_account'
|
|
14
|
+
require_relative 'types/oauth_client'
|
|
15
|
+
require_relative 'types/user'
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'graphql'
|
|
4
|
+
|
|
5
|
+
module Osso
|
|
6
|
+
module GraphQL
|
|
7
|
+
module Types
|
|
8
|
+
class EnterpriseAccount < Types::BaseObject
|
|
9
|
+
description 'An Account for a company that wishes to use SAML via Osso'
|
|
10
|
+
implements ::GraphQL::Types::Relay::Node
|
|
11
|
+
|
|
12
|
+
global_id_field :gid
|
|
13
|
+
field :id, ID, null: false
|
|
14
|
+
field :name, String, null: false
|
|
15
|
+
field :domain, String, null: false
|
|
16
|
+
field :identity_providers, [Types::IdentityProvider], null: true
|
|
17
|
+
field :status, String, null: false
|
|
18
|
+
|
|
19
|
+
def status
|
|
20
|
+
'active'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def identity_providers
|
|
24
|
+
object.identity_providers
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def self.authorized?(object, context)
|
|
28
|
+
super && (context[:scope] == :admin || object.domain == context[:scope])
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'graphql'
|
|
4
|
+
|
|
5
|
+
module Osso
|
|
6
|
+
module GraphQL
|
|
7
|
+
module Types
|
|
8
|
+
class IdentityProvider < Types::BaseObject
|
|
9
|
+
description 'Represents a SAML based IDP instance for an EnterpriseAccount'
|
|
10
|
+
implements ::GraphQL::Types::Relay::Node
|
|
11
|
+
|
|
12
|
+
global_id_field :gid
|
|
13
|
+
field :id, ID, null: false
|
|
14
|
+
field :enterprise_account_id, ID, null: false
|
|
15
|
+
field :service, Types::IdentityProviderService, null: true
|
|
16
|
+
field :domain, String, null: false
|
|
17
|
+
field :acs_url, String, null: false
|
|
18
|
+
field :sso_url, String, null: true
|
|
19
|
+
field :sso_cert, String, null: true
|
|
20
|
+
field :configured, Boolean, null: false
|
|
21
|
+
field :documentation_pdf_url, String, null: true
|
|
22
|
+
|
|
23
|
+
def configured
|
|
24
|
+
!!(@object.sso_url && @object.sso_cert)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def documentation_pdf_url
|
|
28
|
+
ENV['BASE_URL'] + '/identity_provider/documentation/' + @object.id
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.authorized?(object, context)
|
|
32
|
+
super && (context[:scope] == :admin || object.domain == context[:scope])
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Osso
|
|
4
|
+
module GraphQL
|
|
5
|
+
module Types
|
|
6
|
+
class IdentityProviderService < BaseEnum
|
|
7
|
+
value('AZURE', 'Microsoft Azure Identity Provider', value: 'Osso::Models::AzureSamlProvider')
|
|
8
|
+
value('OKTA', 'Okta Identity Provider', value: 'Osso::Models::OktaSamlProvider')
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'graphql'
|
|
4
|
+
|
|
5
|
+
module Osso
|
|
6
|
+
module GraphQL
|
|
7
|
+
module Types
|
|
8
|
+
class OAuthClient < Types::BaseObject
|
|
9
|
+
description 'An OAuth client used to consume Osso SAML users'
|
|
10
|
+
implements ::GraphQL::Types::Relay::Node
|
|
11
|
+
|
|
12
|
+
global_id_field :gid
|
|
13
|
+
field :id, ID, null: false
|
|
14
|
+
field :name, String, null: false
|
|
15
|
+
field :client_id, String, null: false
|
|
16
|
+
field :client_secret, String, null: false
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'graphql'
|
|
4
|
+
require_relative 'base_object'
|
|
5
|
+
|
|
6
|
+
module Osso
|
|
7
|
+
module GraphQL
|
|
8
|
+
module Types
|
|
9
|
+
class User < Types::BaseObject
|
|
10
|
+
description 'A User of the application'
|
|
11
|
+
|
|
12
|
+
field :id, ID, null: false
|
|
13
|
+
field :name, String, null: true
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Osso
|
|
4
|
+
module Helpers
|
|
5
|
+
module Auth
|
|
6
|
+
attr_accessor :current_scope
|
|
7
|
+
|
|
8
|
+
def enterprise_protected!(domain = nil)
|
|
9
|
+
return if admin_authorized?
|
|
10
|
+
return if enterprise_authorized?(domain)
|
|
11
|
+
|
|
12
|
+
halt 401 if request.post?
|
|
13
|
+
|
|
14
|
+
redirect ENV['JWT_URL']
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def enterprise_authorized?(_domain)
|
|
18
|
+
payload, _args = JWT.decode(
|
|
19
|
+
token,
|
|
20
|
+
ENV['JWT_HMAC_SECRET'],
|
|
21
|
+
true,
|
|
22
|
+
{ algorithm: 'HS256' },
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
@current_scope = payload['scope']
|
|
26
|
+
|
|
27
|
+
true
|
|
28
|
+
rescue JWT::DecodeError
|
|
29
|
+
false
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def admin_protected!
|
|
33
|
+
return if admin_authorized?
|
|
34
|
+
|
|
35
|
+
redirect ENV['JWT_URL']
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def admin_authorized?
|
|
39
|
+
payload, _args = JWT.decode(
|
|
40
|
+
token,
|
|
41
|
+
ENV['JWT_HMAC_SECRET'],
|
|
42
|
+
true,
|
|
43
|
+
{ algorithm: 'HS256' },
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
if payload['scope'] == 'admin'
|
|
47
|
+
@current_scope = :admin
|
|
48
|
+
return true
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
false
|
|
52
|
+
rescue JWT::DecodeError
|
|
53
|
+
false
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def token
|
|
57
|
+
request.env['admin_token'] || session['admin_token'] || request['admin_token']
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def chomp_token
|
|
61
|
+
return unless request['admin_token'].present?
|
|
62
|
+
|
|
63
|
+
session['admin_token'] = request['admin_token']
|
|
64
|
+
|
|
65
|
+
return if request.post?
|
|
66
|
+
|
|
67
|
+
redirect request.path
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rack/contrib'
|
|
4
|
+
|
|
5
|
+
module Osso
|
|
6
|
+
module AppConfig
|
|
7
|
+
def self.included(klass)
|
|
8
|
+
klass.class_eval do
|
|
9
|
+
use Rack::JSONBodyParser
|
|
10
|
+
use Rack::Session::Cookie, secret: ENV['SESSION_SECRET']
|
|
11
|
+
|
|
12
|
+
error ActiveRecord::RecordNotFound do
|
|
13
|
+
status 404
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
set :root, Dir.pwd
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module Osso
|
|
6
|
+
module OAuth2Token
|
|
7
|
+
def self.included(klass)
|
|
8
|
+
klass.class_eval do
|
|
9
|
+
cattr_accessor :default_lifetime
|
|
10
|
+
self.default_lifetime = 1.minute
|
|
11
|
+
belongs_to :user
|
|
12
|
+
belongs_to :oauth_client
|
|
13
|
+
|
|
14
|
+
before_validation :setup, on: :create
|
|
15
|
+
validates :oauth_client, :expires_at, presence: true
|
|
16
|
+
validates :token, presence: true, uniqueness: true
|
|
17
|
+
|
|
18
|
+
scope :valid, -> { where('expires_at > ?', Time.now.utc) }
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def expires_in
|
|
23
|
+
(expires_at - Time.now.utc).to_i
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def expired!
|
|
27
|
+
self.expires_at = Time.now.utc
|
|
28
|
+
save!
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def setup
|
|
34
|
+
self.token = SecureRandom.hex(32)
|
|
35
|
+
self.expires_at ||= default_lifetime.from_now
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rubocop:disable Metrics/MethodLength
|
|
4
|
+
|
|
5
|
+
module Osso
|
|
6
|
+
module RouteMap
|
|
7
|
+
def self.included(klass)
|
|
8
|
+
klass.class_eval do
|
|
9
|
+
use Osso::Admin
|
|
10
|
+
use Osso::Auth
|
|
11
|
+
use Osso::Oauth
|
|
12
|
+
|
|
13
|
+
post '/graphql' do
|
|
14
|
+
enterprise_protected!
|
|
15
|
+
|
|
16
|
+
result = Osso::GraphQL::Schema.execute(
|
|
17
|
+
params[:query],
|
|
18
|
+
variables: params[:variables],
|
|
19
|
+
context: { scope: current_scope },
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
json result
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
# rubocop:enable Metrics/MethodLength
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Osso
|
|
4
|
+
module Models
|
|
5
|
+
class AccessToken < ::ActiveRecord::Base
|
|
6
|
+
include OAuth2Token
|
|
7
|
+
self.default_lifetime = 10.minutes
|
|
8
|
+
belongs_to :refresh_token
|
|
9
|
+
|
|
10
|
+
def to_bearer_token
|
|
11
|
+
Rack::OAuth2::AccessToken::Bearer.new(
|
|
12
|
+
access_token: token,
|
|
13
|
+
expires_in: expires_in,
|
|
14
|
+
)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
private
|
|
18
|
+
|
|
19
|
+
def setup
|
|
20
|
+
super
|
|
21
|
+
return unless refresh_token
|
|
22
|
+
|
|
23
|
+
self.user = refresh_token.user
|
|
24
|
+
self.client = refresh_token.client
|
|
25
|
+
self.expires_at = [expires_at, refresh_token.expires_at].min
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Osso
|
|
4
|
+
module Models
|
|
5
|
+
class AuthorizationCode < ActiveRecord::Base
|
|
6
|
+
include OAuth2Token
|
|
7
|
+
|
|
8
|
+
def access_token
|
|
9
|
+
@access_token ||= expired! &&
|
|
10
|
+
user.access_tokens.create(oauth_client: oauth_client)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Osso
|
|
4
|
+
module Models
|
|
5
|
+
# Base class for Enterprises. This should map one-to-one with
|
|
6
|
+
# your own Account model. Persisting the EnterpriseAccount id
|
|
7
|
+
# in your application's database is recommended. The table also
|
|
8
|
+
# includes fields for external IDs such that you can persist
|
|
9
|
+
# your ID for an account in your Osso instance.
|
|
10
|
+
class EnterpriseAccount < ActiveRecord::Base
|
|
11
|
+
belongs_to :oauth_client
|
|
12
|
+
has_many :users
|
|
13
|
+
has_many :identity_providers
|
|
14
|
+
|
|
15
|
+
def single_provider?
|
|
16
|
+
identity_providers.one?
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def provider
|
|
20
|
+
return nil unless single_provider?
|
|
21
|
+
|
|
22
|
+
identity_providers.first
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
alias identity_provider provider
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Osso
|
|
4
|
+
module Models
|
|
5
|
+
# Base class for SAML Providers
|
|
6
|
+
class IdentityProvider < ActiveRecord::Base
|
|
7
|
+
NAME_FORMAT = 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'
|
|
8
|
+
belongs_to :enterprise_account
|
|
9
|
+
belongs_to :oauth_client
|
|
10
|
+
has_many :users
|
|
11
|
+
|
|
12
|
+
def name
|
|
13
|
+
service.titlecase
|
|
14
|
+
# raise(
|
|
15
|
+
# NoMethodError,
|
|
16
|
+
# '#name must be defined on each provider specific subclass',
|
|
17
|
+
# )
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def saml_options
|
|
21
|
+
attributes.slice(
|
|
22
|
+
'domain',
|
|
23
|
+
'idp_cert',
|
|
24
|
+
'idp_sso_target_url',
|
|
25
|
+
).symbolize_keys
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# def saml_options
|
|
29
|
+
# raise(
|
|
30
|
+
# NoMethodError,
|
|
31
|
+
# '#saml_options must be defined on each provider specific subclass',
|
|
32
|
+
# )
|
|
33
|
+
# end
|
|
34
|
+
|
|
35
|
+
def assertion_consumer_service_url
|
|
36
|
+
[
|
|
37
|
+
ENV.fetch('BASE_URL'),
|
|
38
|
+
'auth',
|
|
39
|
+
'saml',
|
|
40
|
+
id,
|
|
41
|
+
'callback',
|
|
42
|
+
].join('/')
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
alias acs_url assertion_consumer_service_url
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|