class Asperalm::Oauth
implement OAuth 2 for the REST client and generate a bearer token call get_authorization
() to get a token. bearer tokens are kept in memory and also in a file cache for later re-use if a token is expired (api returns 4xx), call again get_authorization
({:refresh=>true})
Constants
- JWT_EXPIRY_OFFSET
one hour validity (TODO: configurable?)
- JWT_NOTBEFORE_OFFSET
remove 5 minutes to account for time offset (TODO: configurable?)
- THANK_YOU_HTML
Public Class Methods
open the login page, wait for code and return parameters
# File lib/asperalm/oauth.rb, line 273 def self.goto_page_and_get_request(redirect_uri,login_page_url,html_page=THANK_YOU_HTML) Log.log.info "login_page_url=#{login_page_url}".bg_red().gray() # browser start is not blocking, we hope here that starting is slower than opening port OpenApplication.instance.uri(login_page_url) port=URI.parse(redirect_uri).port Log.log.info "listening on port #{port}" request_params=nil TCPServer.open('127.0.0.1', port) { |webserver| Log.log.info "server=#{webserver}" websession = webserver.accept sleep 1 # TODO: sometimes: returns nil ? use webrick ? line = websession.gets.chomp Log.log.info "line=#{line}" if ! line.start_with?('GET /?') then raise "unexpected request" end request = line.partition('?').last.partition(' ').first data=URI.decode_www_form(request) request_params=data.to_h Log.log.debug "request_params=#{request_params}" websession.print "HTTP/1.1 200/OK\r\nContent-type:text/html\r\n\r\n#{html_page}" websession.close } return request_params end
for supported parameters, look in the code for @params parameters are provided all with oauth_ prefix : :base_url :client_id :client_secret :redirect_uri :jwt_audience :jwt_private_key_obj :jwt_subject :path_authorize (default: 'authorize') :path_token (default: 'token') :scope (optional) :grant (one of returned by self.auth_types) :url_token :user_name :user_pass :token_type
# File lib/asperalm/oauth.rb, line 42 def initialize(auth_params) Log.log.debug "auth=#{auth_params}" @params=auth_params.clone # default values # name of field to take as token from result of call to /token @params[:token_field]||='access_token' # default endpoint for /token @params[:path_token]||='token' # default endpoint for /authorize @params[:path_authorize]||='authorize' rest_params={:base_url => @params[:base_url]} if @params.has_key?(:client_id) rest_params.merge!({:auth => { :type => :basic, :username => @params[:client_id], :password => @params[:client_secret] }}) end @token_auth_api=Rest.new(rest_params) if @params.has_key?(:redirect_uri) uri=URI.parse(@params[:redirect_uri]) raise "redirect_uri scheme must be http" unless uri.scheme.start_with?('http') raise "redirect_uri must have a port" if uri.port.nil? # we could check that host is localhost or local address end end
Private Class Methods
OAuth methods supported
# File lib/asperalm/oauth.rb, line 21 def self.auth_types [ :body_userpass, :header_userpass, :web, :jwt, :url_token, :ibm_apikey ] end
Public Instance Methods
Private Instance Methods
# File lib/asperalm/oauth.rb, line 79 def create_token_advanced(rest_params) return @token_auth_api.call({ :operation => 'POST', :subpath => @params[:path_token], :headers => {'Accept'=>'application/json'}}.merge(rest_params)) end
shortcut for create_token_advanced
# File lib/asperalm/oauth.rb, line 87 def create_token_www_body(creation_params) return create_token_advanced({:www_body_params=>creation_params}) end
open the login page, wait for code and check_code, then return code
# File lib/asperalm/oauth.rb, line 72 def goto_page_and_get_code(login_page_url,check_code) request_params=self.class.goto_page_and_get_request(@params[:redirect_uri],login_page_url) Log.log.error("state does not match") if !check_code.eql?(request_params['state']) code=request_params['code'] return code end
@return String
a unique identifier of token
# File lib/asperalm/oauth.rb, line 92 def token_cache_id(api_scope) oauth_uri=URI.parse(@params[:base_url]) parts=[oauth_uri.host.downcase.gsub(/[^a-z]+/,'_'),oauth_uri.path.downcase.gsub(/[^a-z]+/,'_'),@params[:grant]] parts.push(api_scope) unless api_scope.nil? parts.push(@params[:jwt_subject]) if @params.has_key?(:jwt_subject) parts.push(@params[:user_name]) if @params.has_key?(:user_name) parts.push(@params[:url_token]) if @params.has_key?(:url_token) parts.push(@params[:api_key]) if @params.has_key?(:api_key) return OauthCache.ids_to_id(parts) end