# frozen_string_literal: truerequire_relative"gs2_header"moduleNetclassIMAP<ProtocolmoduleSASL# Abstract base class for the SASL mechanisms defined in# RFC7628[https://www.rfc-editor.org/rfc/rfc7628]:# * OAUTHBEARER[rdoc-ref:OAuthBearerAuthenticator]# (OAuthBearerAuthenticator)# * OAUTH10AclassOAuthAuthenticatorincludeGS2Header# Authorization identity: an identity to act as or on behalf of. The# identity form is application protocol specific. If not provided or# left blank, the server derives an authorization identity from the# authentication identity. The server is responsible for verifying the# client's credentials and verifying that the identity it associates# with the client's authentication identity is allowed to act as (or on# behalf of) the authorization identity.## For example, an administrator or superuser might take on another role:## imap.authenticate "PLAIN", "root", passwd, authzid: "user"#attr_reader:authzidaliasusernameauthzid# Hostname to which the client connected. (optional)attr_reader:host# Service port to which the client connected. (optional)attr_reader:port# HTTP method. (optional)attr_reader:mthd# HTTP path data. (optional)attr_reader:path# HTTP post data. (optional)attr_reader:post# The query string. (optional)attr_reader:qsaliasqueryqs# Stores the most recent server "challenge". When authentication fails,# this may hold information about the failure reason, as JSON.attr_reader:last_server_response# Creates an RFC7628[https://www.rfc-editor.org/rfc/rfc7628] OAuth# authenticator.## ==== Parameters## See child classes for required parameter(s). The following parameters# are all optional, but it is worth noting that <b>application protocols# are allowed to require</b> #authzid (or other parameters, such as# #host or #port) <b>as are specific server implementations</b>.## * _optional_ #authzid ― Authorization identity to act as or on behalf of.## _optional_ #username — An alias for #authzid.## Note that, unlike some other authenticators, +username+ sets the# _authorization_ identity and not the _authentication_ identity. The# authentication identity is established for the client by the OAuth# token.## * _optional_ #host — Hostname to which the client connected.# * _optional_ #port — Service port to which the client connected.# * _optional_ #mthd — HTTP method# * _optional_ #path — HTTP path data# * _optional_ #post — HTTP post data# * _optional_ #qs — HTTP query string## _optional_ #query — An alias for #qs## Any other keyword parameters are quietly ignored.definitialize(authzid: nil,host: nil,port: nil,username: nil,query: nil,mthd: nil,path: nil,post: nil,qs: nil,**)@authzid=authzid||username@host=host@port=port@mthd=mthd@path=path@post=post@qs=qs||query@done=falseend# The {RFC7628 §3.1}[https://www.rfc-editor.org/rfc/rfc7628#section-3.1]# formatted response.definitial_client_responsekv_pairs={host: host,port: port,mthd: mthd,path: path,post: post,qs: qs,auth: authorization,# authorization is implemented by subclasses}.compact[gs2_header,*kv_pairs.map{|kv|kv.join("=")},"\1"].join("\1")end# Returns initial_client_response the first time, then "<tt>^A</tt>".defprocess(data)@last_server_response=datadone??"\1":initial_client_responseensure@done=trueend# Returns true when the initial client response was sent.## The authentication should not succeed unless this returns true, but it# does *not* indicate success.defdone?;@doneend# Value of the HTTP Authorization header## <b>Implemented by subclasses.</b>defauthorization;raise"must be implemented by subclass"endend# Authenticator for the "+OAUTHBEARER+" SASL mechanism, specified in# RFC7628[https://www.rfc-editor.org/rfc/rfc7628]. Authenticates using# OAuth 2.0 bearer tokens, as described in# RFC6750[https://www.rfc-editor.org/rfc/rfc6750]. Use via# Net::IMAP#authenticate.## RFC6750[https://www.rfc-editor.org/rfc/rfc6750] requires Transport Layer# Security (TLS) to secure the protocol interaction between the client and# the resource server. TLS _MUST_ be used for +OAUTHBEARER+ to protect# the bearer token.classOAuthBearerAuthenticator<OAuthAuthenticator# An OAuth 2.0 bearer token. See {RFC-6750}[https://www.rfc-editor.org/rfc/rfc6750]attr_reader:oauth2_tokenaliassecretoauth2_token# :call-seq:# new(oauth2_token, **options) -> authenticator# new(authzid, oauth2_token, **options) -> authenticator# new(oauth2_token:, **options) -> authenticator## Creates an Authenticator for the "+OAUTHBEARER+" SASL mechanism.## Called by Net::IMAP#authenticate and similar methods on other clients.## ==== Parameters## * #oauth2_token — An OAuth2 bearer token## All other keyword parameters are passed to# {super}[rdoc-ref:OAuthAuthenticator::new] (see OAuthAuthenticator).# The most common ones are:## * _optional_ #authzid ― Authorization identity to act as or on behalf of.## _optional_ #username — An alias for #authzid.## Note that, unlike some other authenticators, +username+ sets the# _authorization_ identity and not the _authentication_ identity. The# authentication identity is established for the client by# #oauth2_token.## * _optional_ #host — Hostname to which the client connected.# * _optional_ #port — Service port to which the client connected.## Although only oauth2_token is required by this mechanism, it is worth# noting that <b><em>application protocols are allowed to# require</em></b> #authzid (<em>or other parameters, such as</em> #host# _or_ #port) <b><em>as are specific server implementations</em></b>.definitialize(arg1=nil,arg2=nil,oauth2_token: nil,secret: nil,**args,&blk)username,oauth2_token_arg=arg2.nil??[nil,arg1]:[arg1,arg2]super(username: username,**args,&blk)@oauth2_token=oauth2_token||secret||oauth2_token_argorraiseArgumentError,"missing oauth2_token"end# :call-seq:# initial_response? -> true## +OAUTHBEARER+ sends an initial client response.definitial_response?;trueend# Value of the HTTP Authorization headerdefauthorization;"Bearer #{oauth2_token}"endendendendend