Class: SsoOauthServer
- Defined in:
- lib/app/models/sso_oauth_server.rb
Overview
OAuth 2.0 Server
Direct Known Subclasses
Instance Method Summary collapse
-
#auth_code_url(request, parameters = {}) ⇒ Object
Returns a URL to the OAuth 2.0 provider's consent page asking for permissions for the given scopes explicitly.
-
#auth_endpoint ⇒ Object
abstract
URL - The URL for the authorization end point.
-
#clean_user_profile(user_profile) ⇒ Object
abstract
Hash - The user profile using the mapping from this class.
-
#exchange(root_url, code) ⇒ Object
Exchange will convert an authorization code into a token.
-
#extract_token(vals) ⇒ Object
Token will come in the following schema (hopefully).
- #get_profile(access_token) ⇒ Hash abstract
-
#profile_endpoint ⇒ Object
abstract
Profile end point.
-
#profile_key_mapping ⇒ Object
abstract
Hash - Mapping of key names for the user profile.
-
#redirect_uri(root_url = SystemConfiguration.base_url) ⇒ Object
abstract
URL - Redirect URL for this server.
- #requested_scopes ⇒ Object abstract
-
#response_values(response) ⇒ Object
Based on the response content type get a hash of values.
-
#token_endpoint ⇒ Object
abstract
URL - the Token endpoint.
-
#user_profile(code) ⇒ Object
abstract
Hash - User profile as a hash.
Methods inherited from SsoServer
#display_instructions, #display_name
Instance Method Details
#auth_code_url(request, parameters = {}) ⇒ Object
Returns a URL to the OAuth 2.0 provider's consent page asking for permissions for the given scopes explicitly.
State is a token to protect the user from CSRF attacks. You must always provide a non-zero string and validate that it matches the state query parameter on your redirect callback.
99 100 101 102 103 104 105 106 107 108 |
# File 'lib/app/models/sso_oauth_server.rb', line 99 def auth_code_url(request, parameters = {}) super uri = URI(auth_endpoint) uri.query = parameters.merge(response_type: 'code', client_id: client_id, redirect_uri: redirect_uri, scope: requested_scopes.join(' '), state: request.state).to_query uri.to_s end |
#auth_endpoint ⇒ Object
OAuth 2.0 provider's authorization endpoint URL
Returns URL - The URL for the authorization end point.
55 56 57 58 59 |
# File 'lib/app/models/sso_oauth_server.rb', line 55 def auth_endpoint return nil if server_url.blank? || auth_url.blank? prefix_server auth_url end |
#clean_user_profile(user_profile) ⇒ Object
Clean up the user profile to only return what is listed in the key mapping. Not everything
Returns Hash - The user profile using the mapping from this class.
45 46 47 48 49 50 51 |
# File 'lib/app/models/sso_oauth_server.rb', line 45 def clean_user_profile(user_profile) profile = {} profile_key_mapping.each do |key, value| profile[key] = user_profile[value] end profile end |
#exchange(root_url, code) ⇒ Object
Exchange will convert an authorization code into a token.
113 114 115 116 117 118 119 120 121 122 |
# File 'lib/app/models/sso_oauth_server.rb', line 113 def exchange(root_url, code) response = send_request_for_exchange(root_url, code) log_debug response.body.inspect raise 'Cannot fetch token' unless response.code.between? 200, 299 extract_token(response_values(response)) rescue StandardError => error log_error 'Unable to retrieve profile', error nil end |
#extract_token(vals) ⇒ Object
Token will come in the following schema (hopefully)
- AccessToken: access_token
- TokenType: token_type
- Refresh Token: refresh_token
- Expiry: expires_in, expires (thank you FB)
158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/app/models/sso_oauth_server.rb', line 158 def extract_token(vals) log_debug "extract_token: #{vals.inspect}" token = SsoOauthToken.new token.access_token = vals['access_token'] token.token_type = vals['token_type'] token.refresh_token = vals['refresh_token'] # Convert `e` to integer and then to a time e = vals['expires_in'] e = vals['expires'] if e.blank? token.expiry = Time.now.utc + e.to_i.seconds unless e.blank? token end |
#get_profile(access_token) ⇒ Hash
Get the profile given an access token, can be overriden by concrete implementations.
127 128 129 130 131 132 |
# File 'lib/app/models/sso_oauth_server.rb', line 127 def get_profile(access_token) log_debug "get_profile profile_endpoint: #{profile_endpoint} with token: #{access_token.inspect}" response = RestClient.get(profile_endpoint, Authorization: access_token.) log_debug "get_profile response: #{response.body}" response_values(response) end |
#profile_endpoint ⇒ Object
OAuth 2.0 provider's profile endpoint URL
Returns Profile end point.
71 72 73 74 75 |
# File 'lib/app/models/sso_oauth_server.rb', line 71 def profile_endpoint return nil if server_url.blank? || profile_url.blank? prefix_server profile_url end |
#profile_key_mapping ⇒ Object
Default mapping of user profile keys to what the caller is expecting
Returns Hash - Mapping of key names for the user profile.
39 40 41 |
# File 'lib/app/models/sso_oauth_server.rb', line 39 def profile_key_mapping @profile_key_mapping ||= { name: 'name', email: 'email' } end |
#redirect_uri(root_url = SystemConfiguration.base_url) ⇒ Object
URL to redirect users to going through the flow
Returns URL - Redirect URL for this server.
79 80 81 82 83 |
# File 'lib/app/models/sso_oauth_server.rb', line 79 def redirect_uri(root_url = SystemConfiguration.base_url) return root_url if redirect_path.blank? || root_url.blank? [root_url, (root_url.end_with?('/') ? '' : '/'), redirect_path.gsub(%r{^/+}, '')].join end |
#requested_scopes ⇒ Object
Scope specifies optional requested permissions
87 88 89 |
# File 'lib/app/models/sso_oauth_server.rb', line 87 def requested_scopes scopes.present? ? scopes.split(' ') : [] end |
#response_values(response) ⇒ Object
Based on the response content type get a hash of values.
137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/app/models/sso_oauth_server.rb', line 137 def response_values(response) log_debug "response_values response: #{response.inspect}" case response.headers[:content_type] when 'application/x-www-form-urlencoded', 'text/plain' log_debug "form or plain text response: #{response.body}" log_debug Rack::Utils.parse_nested_query(response.body).inspect Rack::Utils.parse_nested_query(response.body) else log_debug "json: #{response.body}" JSON.parse(response.body) end end |
#token_endpoint ⇒ Object
OAuth 2.0 provider's token endpoint URL
Returns URL - the Token endpoint.
63 64 65 66 67 |
# File 'lib/app/models/sso_oauth_server.rb', line 63 def token_endpoint return nil if server_url.blank? || token_url.blank? prefix_server token_url end |
#user_profile(code) ⇒ Object
Using the appropriate SSO server configuration obtain the user profile address
Returns Hash - User profile as a hash.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/app/models/sso_oauth_server.rb', line 22 def user_profile(code) # Exchange the code to validate the token token = exchange(SystemConfiguration.base_url, code) log_debug "user_profile token: #{token.inspect}" raise 'Invalid token' unless token.present? && token.valid? # Get scoped information using the access token user_profile = get_profile(token) log_debug "user_profile user_profile: #{user_profile.inspect}" raise 'Failed to retrieve user profile from provider' if user_profile.blank? # user_profile.symbolize_keys clean_user_profile(user_profile) end |