Class: CF::UAA::StubUAAConn

Inherits:
Stub::Base show all
Defined in:
lib/uaa/stub/uaa.rb

Class Attribute Summary collapse

Attributes inherited from Stub::Base

#match, #reply, #request, #server

Instance Method Summary collapse

Methods inherited from Stub::Base

find_route, #initialize, #process, #reply_in_kind, route

Constructor Details

This class inherits a constructor from Stub::Base

Class Attribute Details

.authcode_storeObject

Returns the value of attribute authcode_store.



276
277
278
# File 'lib/uaa/stub/uaa.rb', line 276

def authcode_store
  @authcode_store
end

Instance Method Details

#access_denied(msg = 'access denied') ⇒ Object



35
# File 'lib/uaa/stub/uaa.rb', line 35

def access_denied(msg = 'access denied') reply_in_kind(403, error: 'access_denied', error_description: msg) end

#assign_auth_code(client_id, user_id, scope, redir_uri) ⇒ Object



277
278
279
280
281
282
283
# File 'lib/uaa/stub/uaa.rb', line 277

def assign_auth_code(client_id, user_id, scope, redir_uri)
  code = SecureRandom.base64(8)
  raise 'authcode collision' if self.class.authcode_store[code]
  self.class.authcode_store[code] = {client_id: client_id, user_id: user_id,
      scope: scope, redir_uri: redir_uri}
  code
end

#auth_client(basic_auth_header) ⇒ Object



167
168
169
170
171
172
173
# File 'lib/uaa/stub/uaa.rb', line 167

def auth_client(basic_auth_header)
  ah = basic_auth_header.split(' ')
  return unless ah[0] =~ /^basic$/i
  ah = Base64::strict_decode64(ah[1]).split(':')
  client = server.scim.get_by_name(ah[0], :client)
  client if client && client[:client_secret] == ah[1]
end

#bad_params?(params, required, optional = nil) ⇒ Boolean

if required and optional arrays are given, extra params are an error

Returns:

  • (Boolean)


258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/uaa/stub/uaa.rb', line 258

def bad_params?(params, required, optional = nil)
  required.each {|r|
    next if params[r]
    reply.json(400, error: 'invalid_request', error_description: "no #{r} in request")
    return true
  }
  return false unless optional
  params.each {|k, v|
    next if required.include?(k) || optional.include?(k)
    reply.json(400, error: 'invalid_request', error_description: "#{k} not allowed")
    return true
  }
  false
end

#bad_request(msg = nil) ⇒ Object



33
# File 'lib/uaa/stub/uaa.rb', line 33

def bad_request(msg = nil); reply_in_kind(400, error: "bad request#{msg ? ',' : ''} #{msg}") end

#calc_scope(client, user, requested_scope) ⇒ Object

returns granted scopes TODO: doesn’t handle actual user authorization yet



204
205
206
207
208
209
210
211
# File 'lib/uaa/stub/uaa.rb', line 204

def calc_scope(client, user, requested_scope)
  possible_scope = ids_to_names(client[user ? :scope : :authorities])
  requested_scope = Util.arglist(requested_scope) || []
  return unless (requested_scope - possible_scope).empty?
  requested_scope = possible_scope if requested_scope.empty?
  granted_scopes = user ? (ids_to_names(user[:groups]) & requested_scope) : requested_scope # handle auto-deny
  Util.strlist(granted_scopes) unless granted_scopes.empty?
end

#client_to_scim(info) ⇒ Object


client endpoints



354
355
356
357
# File 'lib/uaa/stub/uaa.rb', line 354

def client_to_scim(info)
  ['authorities', 'scope', 'autoapprove'].each { |a| info[a] = names_to_ids(info[a], :group) if info.key?(a) }
  info
end


39
# File 'lib/uaa/stub/uaa.rb', line 39

def decode_cookie(str) Util.json.decode64(str) end

#default_routeObject


miscellaneous endpoints



65
# File 'lib/uaa/stub/uaa.rb', line 65

def default_route; reply_in_kind(404, error: 'not found', error_description: "unknown path #{request.path}") end


38
# File 'lib/uaa/stub/uaa.rb', line 38

def encode_cookie(obj = {}) Util.json_encode64(obj) end

#find_user(name, pwd = nil) ⇒ Object



56
57
58
59
# File 'lib/uaa/stub/uaa.rb', line 56

def find_user(name, pwd = nil)
  user = server.scim.get_by_name(name, :user, :password, :id, :emails, :username, :groups)
  user if user && (!pwd || user[:password] == pwd)
end

#ids_to_names(ids) ⇒ Object



36
# File 'lib/uaa/stub/uaa.rb', line 36

def ids_to_names(ids); ids ? ids.map { |id| server.scim.name(id) } : [] end

#inject_error(input = nil) ⇒ Object



24
25
26
27
28
29
30
31
# File 'lib/uaa/stub/uaa.rb', line 24

def inject_error(input = nil)
  case server.reply_badly
  when :non_json then reply.text('non-json reply')
  when :bad_json then reply.body = '{"access_token":"good.access.token" "missed a comma":"there"}'
  when :bad_state then input[:state] = 'badstate'
  when :no_token_type then input.delete(:token_type)
  end
end

#names_to_ids(names, rtype) ⇒ Object



37
# File 'lib/uaa/stub/uaa.rb', line 37

def names_to_ids(names, rtype); names ? names.map { |name| server.scim.id(name, rtype) } : [] end

#not_found(name = nil) ⇒ Object



34
# File 'lib/uaa/stub/uaa.rb', line 34

def not_found(name = nil); reply_in_kind(404, error: "#{name} not found") end

#obj_access?(rtype, oid, perm) ⇒ Boolean

Returns:

  • (Boolean)


426
427
428
429
430
431
432
# File 'lib/uaa/stub/uaa.rb', line 426

def obj_access?(rtype, oid, perm)
  major_scope = perm == :writers ? 'scim.write' : 'scim.read'
  return unless tkn = valid_token("#{major_scope} scim.me")
  return tkn if tkn['scope'].include?(major_scope) ||
      rtype == :group && server.scim.is_member(oid, tkn['user_id'], perm)
  access_denied
end

#page_query(rtype, query, attrs, acl = nil, acl_id = nil) ⇒ Object



493
494
495
496
497
498
499
500
501
502
503
504
505
# File 'lib/uaa/stub/uaa.rb', line 493

def page_query(rtype, query, attrs, acl = nil, acl_id = nil)
  if query['attributes']
    attrs = attrs & Util.arglist(query['attributes']).each_with_object([]) {|a, o|
      o << a.to_sym if StubScim::ATTR_NAMES.include?(a = a.downcase)
    }
  end
  start = sanitize_int(query['startindex'], 1, 1)
  count = sanitize_int(query['count'], 15, 1, 3000)
  return bad_request('invalid startIndex or count') unless start && count
  info, total = server.scim.find(rtype, start: start - 1, count: count,
      filter: query['filter'], attrs: attrs, acl: acl, acl_id: acl_id)
  reply_in_kind(resources: info, itemsPerPage: info.length, startIndex: start, totalResults: total)
end

#primary_email(emails) ⇒ Object



49
50
51
52
53
54
# File 'lib/uaa/stub/uaa.rb', line 49

def primary_email(emails)
  return unless emails
  emails.each {|e| return e[:value] if e[:type] && e[:type] == 'primary'
  }
  emails[0][:value]
end

#redeem_auth_code(client_id, redir_uri, code) ⇒ Object



284
285
286
287
288
# File 'lib/uaa/stub/uaa.rb', line 284

def redeem_auth_code(client_id, redir_uri, code)
  return unless info = self.class.authcode_store.delete(code)
  return unless info[:client_id] == client_id && info[:redir_uri] == redir_uri
  [info[:user_id], info[:scope]]
end

#redir_err_f(cburi, state, msg) ⇒ Object



199
# File 'lib/uaa/stub/uaa.rb', line 199

def redir_err_f(cburi, state, msg); redir_with_fragment(cburi, error: msg, state: state) end

#redir_err_q(cburi, state, msg) ⇒ Object



200
# File 'lib/uaa/stub/uaa.rb', line 200

def redir_err_q(cburi, state, msg); redir_with_query(cburi, error: msg, state: state) end

#redir_with_fragment(cburi, params) ⇒ Object



185
186
187
188
189
190
# File 'lib/uaa/stub/uaa.rb', line 185

def redir_with_fragment(cburi, params)
  reply.status = 302
  uri = URI.parse(cburi)
  uri.fragment = Util.encode_form(params)
  reply.headers[:location] = uri.to_s
end

#redir_with_query(cburi, params) ⇒ Object



192
193
194
195
196
197
# File 'lib/uaa/stub/uaa.rb', line 192

def redir_with_query(cburi, params)
  reply.status = 302
  uri = URI.parse(cburi)
  uri.query = Util.encode_form(params)
  reply.headers[:location] = uri.to_s
end

#sanitize_int(arg, default, min, max = nil) ⇒ Object



487
488
489
490
491
# File 'lib/uaa/stub/uaa.rb', line 487

def sanitize_int(arg, default, min, max = nil)
  return default if arg.nil?
  return unless arg.to_i.to_s == arg && (i = arg.to_i) >= min
  max && i > max ? max : i
end

#scim_to_client(info) ⇒ Object



359
360
361
362
363
# File 'lib/uaa/stub/uaa.rb', line 359

def scim_to_client(info)
  [:authorities, :scope, :autoapprove].each { |a| info[a] = ids_to_names(info[a]) if info.key?(a) }
  info.delete(:id)
  info
end

#token_reply_info(client, scope, user = nil, state = nil, refresh = false) ⇒ Object

current uaa token contents: exp, user_name, scope, email, user_id,

client_id, client_authorities, user_authorities


150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/uaa/stub/uaa.rb', line 150

def token_reply_info(client, scope, user = nil, state = nil, refresh = false)
  interval = client[:access_token_validity] || 3600
  token_body = { jti: SecureRandom.uuid, aud: scope, scope: scope,
      client_id: client[:client_id], exp: interval + Time.now.to_i }
  if user
    token_body[:user_id] = user[:id]
    token_body[:email] = primary_email(user[:emails])
    token_body[:user_name] = user[:username]
  end
  info = { access_token: TokenCoder.encode(token_body, :algorithm => 'none'),
      token_type: 'bearer', expires_in: interval, scope: scope}
  info[:state] = state if state
  info[:refresh_token] = 'universal_refresh_token' if refresh
  inject_error(info)
  info
end

#valid_redir_uri?(client, redir_uri) ⇒ Boolean

Returns:

  • (Boolean)


175
176
177
178
179
180
181
182
183
# File 'lib/uaa/stub/uaa.rb', line 175

def valid_redir_uri?(client, redir_uri)
  t = URI.parse(redir_uri)
  return true unless (ruris = client[:redirect_uris]) && !ruris.empty?
  false unless ruris.each { |reg_uri|
    r = URI.parse(reg_uri)
    return true if r.scheme == t.scheme && r.host == t.host &&
        (!r.port || r.port == t.port) && (!r.path || r.path == t.path)
  }
end

#valid_token(accepted_scope) ⇒ Object



41
42
43
44
45
46
47
# File 'lib/uaa/stub/uaa.rb', line 41

def valid_token(accepted_scope)
  return nil unless (ah = request.headers['authorization']) && (ah = ah.split(' '))[0] =~ /^bearer$/i
  contents = TokenCoder.decode(ah[1], accept_algorithms: 'none')
  contents['scope'], accepted_scope = Util.arglist(contents['scope']), Util.arglist(accepted_scope)
  return contents if accepted_scope.nil? || !(accepted_scope & contents['scope']).empty?
  access_denied("accepted scope #{Util.strlist(accepted_scope)}")
end