authproto 0.3.0.beta1

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.
Files changed (115) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +1 -0
  3. data/.rubocop.yml +31 -0
  4. data/.tm_properties +1 -0
  5. data/.yardopts +4 -0
  6. data/CHANGELOG.md +52 -0
  7. data/MIT-LICENSE.txt +21 -0
  8. data/README.md +304 -0
  9. data/Rakefile +8 -0
  10. data/SECURITY.md +16 -0
  11. data/examples/confidential_client/.gitignore +5 -0
  12. data/examples/confidential_client/Gemfile +14 -0
  13. data/examples/confidential_client/Gemfile.lock +88 -0
  14. data/examples/confidential_client/README.md +226 -0
  15. data/examples/confidential_client/app.rb +290 -0
  16. data/examples/confidential_client/config/client-metadata.example.json +25 -0
  17. data/examples/confidential_client/config.ru +4 -0
  18. data/examples/confidential_client/public/styles.css +70 -0
  19. data/examples/confidential_client/screenshots/screenshot-1-sign-in.png +0 -0
  20. data/examples/confidential_client/screenshots/screenshot-2-success.png +0 -0
  21. data/examples/confidential_client/scripts/generate_keys.rb +15 -0
  22. data/examples/confidential_client/views/authorized.erb +46 -0
  23. data/examples/confidential_client/views/index.erb +44 -0
  24. data/examples/confidential_client/views/layout.erb +11 -0
  25. data/examples/minisky_console/.gitignore +2 -0
  26. data/examples/minisky_console/Gemfile +12 -0
  27. data/examples/minisky_console/Gemfile.lock +131 -0
  28. data/examples/minisky_console/README.md +112 -0
  29. data/examples/minisky_console/app.rb +50 -0
  30. data/examples/minisky_console/bin/console +6 -0
  31. data/examples/minisky_console/config.ru +5 -0
  32. data/examples/minisky_console/localhost.rb +53 -0
  33. data/examples/minisky_console/production.rb +32 -0
  34. data/lib/authproto/client.rb +583 -0
  35. data/lib/authproto/client_metadata.rb +478 -0
  36. data/lib/authproto/configuration.rb +139 -0
  37. data/lib/authproto/dpop/client.rb +161 -0
  38. data/lib/authproto/dpop/key_manager.rb +223 -0
  39. data/lib/authproto/dpop/nonce_manager.rb +145 -0
  40. data/lib/authproto/dpop/proof_generator.rb +124 -0
  41. data/lib/authproto/dpop/stored_nonce.rb +37 -0
  42. data/lib/authproto/encryption.rb +250 -0
  43. data/lib/authproto/errors.rb +75 -0
  44. data/lib/authproto/http_client.rb +320 -0
  45. data/lib/authproto/insecure_http_client.rb +24 -0
  46. data/lib/authproto/localhost_server.rb +274 -0
  47. data/lib/authproto/minisky.rb +273 -0
  48. data/lib/authproto/par/client.rb +240 -0
  49. data/lib/authproto/par/client_assertion.rb +69 -0
  50. data/lib/authproto/par/request.rb +243 -0
  51. data/lib/authproto/par/response.rb +43 -0
  52. data/lib/authproto/par.rb +48 -0
  53. data/lib/authproto/pkce.rb +125 -0
  54. data/lib/authproto/serialization/base.rb +258 -0
  55. data/lib/authproto/serialization/dpop_key.rb +38 -0
  56. data/lib/authproto/serialization/session.rb +88 -0
  57. data/lib/authproto/serialization/stored_nonce.rb +46 -0
  58. data/lib/authproto/serialization/token_set.rb +54 -0
  59. data/lib/authproto/server_metadata/authorization_server.rb +267 -0
  60. data/lib/authproto/server_metadata/origin_url.rb +71 -0
  61. data/lib/authproto/server_metadata/resource_server.rb +98 -0
  62. data/lib/authproto/server_metadata.rb +28 -0
  63. data/lib/authproto/state/session.rb +168 -0
  64. data/lib/authproto/state/session_manager.rb +162 -0
  65. data/lib/authproto/state/token_set.rb +101 -0
  66. data/lib/authproto/state.rb +61 -0
  67. data/lib/authproto/storage/interface.rb +121 -0
  68. data/lib/authproto/storage/key_builder.rb +76 -0
  69. data/lib/authproto/storage/memory.rb +222 -0
  70. data/lib/authproto/storage/redis.rb +156 -0
  71. data/lib/authproto/storage/sqlite.rb +281 -0
  72. data/lib/authproto/token/refresh.rb +414 -0
  73. data/lib/authproto/version.rb +8 -0
  74. data/lib/authproto.rb +18 -0
  75. data/sig/authproto/client.rbs +43 -0
  76. data/sig/authproto/client_metadata.rbs +113 -0
  77. data/sig/authproto/dependencies.rbs +19 -0
  78. data/sig/authproto/dpop/client.rbs +23 -0
  79. data/sig/authproto/dpop/key_manager.rbs +26 -0
  80. data/sig/authproto/dpop/nonce_manager.rbs +23 -0
  81. data/sig/authproto/dpop/proof_generator.rbs +40 -0
  82. data/sig/authproto/dpop/stored_nonce.rbs +10 -0
  83. data/sig/authproto/encryption.rbs +42 -0
  84. data/sig/authproto/http_client.rbs +45 -0
  85. data/sig/authproto/insecure_http_client.rbs +8 -0
  86. data/sig/authproto/localhost_server.rbs +30 -0
  87. data/sig/authproto/minisky_oauth.rbs +22 -0
  88. data/sig/authproto/par/client.rbs +25 -0
  89. data/sig/authproto/par/client_assertion.rbs +10 -0
  90. data/sig/authproto/par/request.rbs +73 -0
  91. data/sig/authproto/par/response.rbs +17 -0
  92. data/sig/authproto/par.rbs +7 -0
  93. data/sig/authproto/pkce.rbs +24 -0
  94. data/sig/authproto/serialization/base.rbs +36 -0
  95. data/sig/authproto/serialization/dpop_key.rbs +14 -0
  96. data/sig/authproto/serialization/session.rbs +19 -0
  97. data/sig/authproto/serialization/stored_nonce.rbs +14 -0
  98. data/sig/authproto/serialization/token_set.rbs +14 -0
  99. data/sig/authproto/server_metadata/authorization_server.rbs +71 -0
  100. data/sig/authproto/server_metadata/origin_url.rbs +21 -0
  101. data/sig/authproto/server_metadata/resource_server.rbs +27 -0
  102. data/sig/authproto/state/session.rbs +28 -0
  103. data/sig/authproto/state/session_manager.rbs +15 -0
  104. data/sig/authproto/state/token_set.rbs +40 -0
  105. data/sig/authproto/state.rbs +6 -0
  106. data/sig/authproto/storage/interface.rbs +20 -0
  107. data/sig/authproto/storage/key_builder.rbs +16 -0
  108. data/sig/authproto/storage/memory.rbs +22 -0
  109. data/sig/authproto/storage/redis.rbs +19 -0
  110. data/sig/authproto/storage/redis_client.rbs +11 -0
  111. data/sig/authproto/storage/sqlite.rbs +26 -0
  112. data/sig/authproto/token/refresh.rbs +47 -0
  113. data/sig/authproto/version.rbs +3 -0
  114. data/sig/authproto.rbs +54 -0
  115. metadata +200 -0
@@ -0,0 +1,40 @@
1
+ module AuthProto
2
+ module DPoP
3
+ class ProofGenerator
4
+ @key_manager: AuthProto::DPoP::KeyManager
5
+
6
+ class ProofError < AuthProto::Error
7
+ end
8
+
9
+ attr_reader key_manager: AuthProto::DPoP::KeyManager
10
+
11
+ def initialize: (AuthProto::DPoP::KeyManager key_manager) -> void
12
+
13
+ def generate: (
14
+ http_method: String,
15
+ http_uri: String,
16
+ ?nonce: String?,
17
+ ?access_token: String?,
18
+ ?ath: bool?
19
+ ) -> JOSE::SignedBinary
20
+
21
+ private
22
+
23
+ def validate_inputs: (String http_method, String http_uri) -> void
24
+
25
+ def build_header: () -> { typ: "dpop+jwt", alg: "ES256", jwk: Hash[String, untyped] }
26
+
27
+ def build_payload: (
28
+ http_method: String,
29
+ http_uri: String,
30
+ ?nonce: String?,
31
+ ?access_token: String?,
32
+ ?include_ath: bool?
33
+ ) -> Hash[String, untyped]
34
+
35
+ def normalize_uri: (String uri) -> String
36
+
37
+ def generate_access_token_hash: (String access_token) -> String
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,10 @@
1
+ module AuthProto
2
+ module DPoP
3
+ class StoredNonce
4
+ attr_reader value: String
5
+ attr_reader server_url: String
6
+ attr_reader timestamp: Integer | Time
7
+ def initialize: (String value, String server_url, ?timestamp: (Integer | Time)?) -> void
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,42 @@
1
+ module AuthProto
2
+ module Encryption
3
+ type envelope = { version: Integer, iv: String, data: String, tag: String }
4
+
5
+ class Error < AuthProto::Error
6
+ end
7
+ class ConfigurationError < Error
8
+ end
9
+ class EncryptionError < Error
10
+ end
11
+ class DecryptionError < Error
12
+ end
13
+
14
+ module HKDF
15
+ def self.derive: (_ToS secret, salt: String, info: String, length: Integer) -> String
16
+ end
17
+
18
+ class Service
19
+ CIPHER: String
20
+ VERSION: Integer
21
+ def initialize: () -> void
22
+ def encrypt: (_ToS data, context: String) -> envelope
23
+ def decrypt: (envelope encrypted, context: String) -> String
24
+
25
+ private
26
+ def validate_encryption_inputs: (untyped data, untyped context) -> void
27
+ def validate_decryption_inputs: (untyped encrypted, untyped context) -> void
28
+ def validate_encrypted_data: (untyped encrypted) -> void
29
+ end
30
+
31
+ class KeyProvider
32
+ EPHEMERAL_KEY_MUTEX: Mutex
33
+ def self.ephemeral_master_key: () -> String
34
+ def initialize: () -> void
35
+ def key_for_context: (String context) -> String
36
+
37
+ private
38
+ def load_master_key: () -> String
39
+ def salt_for_context: (String context) -> String
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,45 @@
1
+ module AuthProto
2
+ class HTTPClient
3
+ FORBIDDEN_IP_RANGES: Array[IPAddr]
4
+ ALLOWED_SCHEMES: Array[String]
5
+ DEFAULT_TIMEOUT: Integer
6
+ MAX_REDIRECTS: Integer
7
+ MAX_RESPONSE_SIZE: Integer
8
+
9
+ class SSRFError < AuthProto::Error
10
+ end
11
+
12
+ class HTTPError < AuthProto::Error
13
+ attr_reader response: Net::HTTPResponse?
14
+ def initialize: (String message, Net::HTTPResponse? response) -> void
15
+ end
16
+
17
+ class RedirectHandlerOptions < Data
18
+ attr_reader original_uri: URI::HTTP
19
+ attr_reader method: Symbol
20
+ attr_reader response: Net::HTTPResponse
21
+ attr_reader headers: Hash[String, String]
22
+ attr_reader redirect_count: Integer
23
+ attr_reader body: http_body
24
+ def self.new: (URI::HTTP original_uri, Symbol method, Net::HTTPResponse response, Hash[String, String] headers, Integer redirect_count, http_body body) -> instance
25
+ | (original_uri: URI::HTTP, method: Symbol, response: Net::HTTPResponse, headers: Hash[String, String], redirect_count: Integer, body: http_body) -> instance
26
+ end
27
+
28
+ def initialize: (?timeout: Numeric, ?verify_ssl: bool) -> void
29
+ def get: (String url, ?Hash[String, String] headers, ?follow_redirects: bool) -> http_response
30
+ def post: (String url, ?body: http_body, ?headers: Hash[String, String]) -> http_response
31
+
32
+ private
33
+ def validate_uri: (String url) -> URI::HTTP
34
+ def validate_ip: (URI::HTTP uri) -> void
35
+ def forbidden_ip?: (IPAddr ip) -> bool
36
+ def make_request: (URI::HTTP uri, ?Hash[String, String] headers, ?Integer redirect_count, ?follow_redirects: bool) -> Net::HTTPResponse
37
+ def make_post_request: (URI::HTTP uri, http_body body, ?Hash[String, String] headers, ?Integer redirect_count) -> Net::HTTPResponse
38
+ def configure_http_client: (Net::HTTP http, ?ssl: bool) -> void
39
+ def add_security_headers: (Net::HTTPRequest request, Hash[String, String] headers) -> void
40
+ def handle_redirect: (original_uri: URI::HTTP, response: Net::HTTPResponse, headers: Hash[String, String], redirect_count: Integer, ?method: Symbol, ?body: http_body) -> Net::HTTPResponse
41
+ def validate_response: (Net::HTTPResponse response) -> void
42
+ def check_success_status: (Net::HTTPResponse response) -> void
43
+ def check_content_length: (Net::HTTPResponse response) -> void
44
+ end
45
+ end
@@ -0,0 +1,8 @@
1
+ module AuthProto
2
+ class InsecureHTTPClient < HTTPClient
3
+ ALLOWED_SCHEMES: Array[String]
4
+
5
+ private
6
+ def validate_ip: (URI::HTTP uri) -> void
7
+ end
8
+ end
@@ -0,0 +1,30 @@
1
+ module AuthProto
2
+ class LocalhostServer
3
+ type metadata = Hash[String | Symbol, untyped]
4
+ type callback_params = { code: String, state: String, iss: String }
5
+
6
+ MAX_HEADER_BYTES: Integer
7
+ REQUEST_TIMEOUT: Integer
8
+ LOOPBACK_RANGES: Array[IPAddr]
9
+
10
+ class CallbackError < StandardError
11
+ attr_reader error_code: String
12
+ attr_reader error_description: String?
13
+ def initialize: (String error_code, String? error_description) -> void
14
+ end
15
+ class InvalidRequest < StandardError
16
+ end
17
+
18
+ def self.start: [T] (metadata metadata, ?timeout: Numeric) { (callback_params) -> T } -> T
19
+ def initialize: (metadata metadata) -> void
20
+ def start: [T] (?timeout: Numeric) { (callback_params) -> T } -> T
21
+
22
+ private
23
+ def loopback_host?: (String? host) -> bool
24
+ def handle_connection: [T] (TCPSocket socket) { (callback_params) -> T } -> [bool, T?]
25
+ def handle_request: (TCPSocket socket) -> Hash[String, String]?
26
+ def read_request: (TCPSocket socket) -> [String, String]
27
+ def extract_callback_params: (URI::Generic uri) -> Hash[String, String]
28
+ def respond: (TCPSocket socket, Integer status, String reason, String body) -> void
29
+ end
30
+ end
@@ -0,0 +1,22 @@
1
+ # Signatures for the methods defined by the optional Minisky adapter.
2
+ # Additional methods mixed in from Minisky::Requests belong to the minisky gem.
3
+ class MiniskyOAuth
4
+ MAX_NONCE_RETRIES: Integer
5
+ attr_reader host: String
6
+ attr_reader oauth_client: AuthProto::Client
7
+ attr_reader session_id: String?
8
+
9
+ def initialize: (String host, client_id: String, redirect_uri: String, ?metadata: AuthProto::json_object?, ?dpop_key: (AuthProto::json_object | JOSE::Map)?) -> void
10
+ def config: () -> nil
11
+ def authorize: (?handle: String?, ?pds_url: String?, ?scope: String) -> AuthProto::authorization_result
12
+ def handle_callback: (code: String, state: String, iss: String) -> AuthProto::callback_result
13
+ def get_request: (String | URI::HTTP method, ?Hash[untyped, untyped]? params, ?auth: bool, ?headers: Hash[String, String]?) -> untyped
14
+ def post_request: (String | URI::HTTP method, ?untyped data, ?auth: bool, ?headers: Hash[String, String]?, ?params: Hash[untyped, untyped]?) -> untyped
15
+ def log_in: (*untyped args) -> bot
16
+ def perform_token_refresh: () -> AuthProto::refreshed_tokens
17
+ def check_access: () -> (:ok | :refreshed)
18
+
19
+ private
20
+ def oauth_request: (singleton(Net::HTTP::Get) | singleton(Net::HTTP::Post) request_class, URI::HTTP url, Hash[String, String] headers, ?body: String?) -> Net::HTTPResponse
21
+ def authentication_error: (Net::HTTPResponse response) -> String?
22
+ end
@@ -0,0 +1,25 @@
1
+ module AuthProto
2
+ module PAR
3
+ class Client
4
+ attr_reader endpoint: String
5
+ attr_reader dpop_client: DPoP::Client
6
+ attr_reader nonce_manager: DPoP::NonceManager
7
+
8
+ def initialize: (endpoint: String, dpop_client: DPoP::Client) -> void
9
+ def submit: (Request request) -> Response
10
+ def extract_nonce: (http_response response) -> String
11
+ def authorization_url: (authorize_endpoint: String, request_uri: String, client_id: String) -> String
12
+
13
+ private
14
+ def validate_endpoint: () -> void
15
+ def make_request: (Request request) -> http_response
16
+ def build_headers: (Request request, String dpop_proof) -> Hash[String, String]
17
+ def requires_nonce?: (http_response response) -> bool
18
+ def store_nonce: (String nonce) -> void
19
+ def server_origin: () -> String
20
+ def handle_error_response: (http_response response) -> bot
21
+ def process_response: (http_response response) -> Response
22
+ def encode_params: (Hash[String, String] params) -> String
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,10 @@
1
+ module AuthProto
2
+ module PAR
3
+ class ClientAssertion
4
+ class Error < AuthProto::Error
5
+ end
6
+ def initialize: (client_id: String, signing_key: JOSE::JWK) -> void
7
+ def generate_jwt: (audience: String, ?lifetime: Integer) -> String
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,73 @@
1
+ module AuthProto
2
+ module PAR
3
+ class Request
4
+ @response_type: String
5
+ @client_id: String
6
+ @redirect_uri: String
7
+ @code_challenge: String
8
+ @code_challenge_method: String
9
+ @state: String
10
+ @scope: String
11
+ @login_hint: String?
12
+ @nonce: String?
13
+ @dpop_proof: String?
14
+ @client_assertion_type: String?
15
+ @client_assertion: String?
16
+
17
+ class Configuration
18
+ attr_accessor client_id: String?
19
+ attr_accessor redirect_uri: String?
20
+ attr_accessor code_challenge: String?
21
+ attr_accessor code_challenge_method: String?
22
+ attr_accessor state: String?
23
+ attr_accessor scope: String?
24
+ attr_accessor login_hint: String?
25
+ attr_accessor nonce: String?
26
+ attr_accessor dpop_proof: String?
27
+ attr_accessor client_assertion_type: String?
28
+ attr_accessor client_assertion: String?
29
+ end
30
+
31
+ attr_reader response_type: String
32
+ attr_reader client_id: String
33
+ attr_reader code_challenge: String
34
+ attr_reader code_challenge_method: String
35
+ attr_reader state: String
36
+ attr_reader redirect_uri: String
37
+ attr_reader scope: String
38
+ attr_reader login_hint: String?
39
+ attr_reader nonce: String?
40
+ attr_reader dpop_proof: String?
41
+ attr_reader client_assertion_type: String?
42
+ attr_reader client_assertion: String?
43
+
44
+ def self.build: () { (Configuration) -> untyped } -> Request
45
+
46
+ def initialize: (Configuration config) -> void
47
+
48
+ def to_form: () -> String
49
+
50
+ private
51
+
52
+ def build_params: () -> Hash[String, String]
53
+
54
+ def add_optional_params: (Hash[String, String] params) -> void
55
+
56
+ def add_client_auth_params: (Hash[String, String] params) -> void
57
+
58
+ def validate_request: () -> void
59
+
60
+ def validate_required_params: () -> void
61
+
62
+ def validate_response_type: () -> void
63
+
64
+ def validate_code_challenge_method: () -> void
65
+
66
+ def validate_scope: () -> void
67
+
68
+ def validate_client_auth: () -> void
69
+
70
+ def encode_params: (Hash[String, String]) -> String
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,17 @@
1
+ module AuthProto
2
+ module PAR
3
+ class Response
4
+ @request_uri: String
5
+ @expires_in: Integer
6
+
7
+ attr_reader request_uri: String
8
+ attr_reader expires_in: Integer
9
+
10
+ def initialize: (request_uri: String, expires_in: Integer | String) -> void
11
+
12
+ private
13
+
14
+ def validate_response: () -> void
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,7 @@
1
+ module AuthProto
2
+ module PAR
3
+ CLIENT_ASSERTION_TYPE: String
4
+ class Error < AuthProto::Error
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,24 @@
1
+ module AuthProto
2
+ module PKCE
3
+ class Error < AuthProto::Error
4
+ end
5
+
6
+ MIN_VERIFIER_LENGTH: Integer
7
+ MAX_VERIFIER_LENGTH: Integer
8
+ ALLOWED_VERIFIER_CHARS: ::Regexp
9
+
10
+ def self.generate_verifier: (?Integer length) -> String
11
+
12
+ def self.generate_challenge: (String verifier) -> String
13
+
14
+ def self.verify: (String challenge, String verifier) -> bool
15
+
16
+ private
17
+
18
+ private def self.validate_verifier_length: (Integer length) -> void
19
+
20
+ private def self.validate_verifier: (String verifier) -> void
21
+
22
+ private def self.secure_compare: (String str1, String str2) -> bool
23
+ end
24
+ end
@@ -0,0 +1,36 @@
1
+ module AuthProto
2
+ module Serialization
3
+ type data_hash = Hash[String | Symbol, untyped]
4
+
5
+ class Error < AuthProto::Error
6
+ end
7
+ class VersionError < Error
8
+ end
9
+ class TypeMismatchError < Error
10
+ end
11
+ class ValidationError < Error
12
+ end
13
+
14
+ class Base[T]
15
+ CURRENT_VERSION: Integer
16
+ SENSITIVE_FIELDS: Array[String]
17
+ def self.serialize: (untyped obj) -> String
18
+ def self.deserialize: (String data) -> untyped
19
+ def initialize: () -> void
20
+ def serialize: (T obj) -> String
21
+ def deserialize: (String data) -> T
22
+
23
+ private
24
+ def encrypt_sensitive_fields: (data_hash data, ?path: Array[String | Symbol]) -> void
25
+ def decrypt_sensitive_fields: (data_hash data, ?path: Array[String | Symbol]) -> void
26
+ def sensitive_field?: (String | Symbol field) -> bool
27
+ def type_identifier: () -> String
28
+ def serialize_data: (T obj) -> data_hash
29
+ def deserialize_data: (json_object data) -> T
30
+ def validate_object: (T obj) -> void
31
+ def parse_json: (String data) -> untyped
32
+ def validate_serialized_data: (untyped data) -> void
33
+ def deserialize_version: (json_object data) -> T
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,14 @@
1
+ module AuthProto
2
+ module Serialization
3
+ class DPoPKey < Base[DPoP::KeyManager]
4
+ def self.serialize: (DPoP::KeyManager obj) -> String
5
+ def self.deserialize: (String data) -> DPoP::KeyManager
6
+ def type_identifier: () -> String
7
+
8
+ private
9
+ def validate_object: (DPoP::KeyManager obj) -> void
10
+ def serialize_data: (DPoP::KeyManager obj) -> json_object
11
+ def deserialize_data: (json_object data) -> DPoP::KeyManager
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ module AuthProto
2
+ module Serialization
3
+ class Session < Base[State::Session]
4
+ def self.serialize: (State::Session obj) -> String
5
+ def self.deserialize: (String data) -> State::Session
6
+ def type_identifier: () -> String
7
+
8
+ private
9
+ def validate_object: (State::Session obj) -> void
10
+ def serialize_data: (State::Session obj) -> data_hash
11
+ def deserialize_data: (json_object data) -> State::Session
12
+
13
+ def serialize_token_set: (State::TokenSet? tokens) -> String?
14
+ def deserialize_token_set: (String? data) -> State::TokenSet?
15
+ def serialize_auth_server: (ServerMetadata::AuthorizationServer? server) -> Hash[Symbol, untyped]?
16
+ def deserialize_auth_server: (json_object? data) -> ServerMetadata::AuthorizationServer?
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ module AuthProto
2
+ module Serialization
3
+ class StoredNonce < Base[DPoP::StoredNonce]
4
+ def self.serialize: (DPoP::StoredNonce obj) -> String
5
+ def self.deserialize: (String data) -> DPoP::StoredNonce
6
+ def type_identifier: () -> String
7
+
8
+ private
9
+ def validate_object: (DPoP::StoredNonce obj) -> void
10
+ def serialize_data: (DPoP::StoredNonce obj) -> data_hash
11
+ def deserialize_data: (json_object data) -> DPoP::StoredNonce
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module AuthProto
2
+ module Serialization
3
+ class TokenSet < Base[State::TokenSet]
4
+ def self.serialize: (State::TokenSet obj) -> String
5
+ def self.deserialize: (String data) -> State::TokenSet
6
+ def type_identifier: () -> String
7
+
8
+ private
9
+ def validate_object: (State::TokenSet obj) -> void
10
+ def serialize_data: (State::TokenSet obj) -> data_hash
11
+ def deserialize_data: (json_object data) -> State::TokenSet
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,71 @@
1
+ module AuthProto
2
+ module ServerMetadata
3
+ class AuthorizationServer
4
+ @issuer: String
5
+ @authorization_endpoint: String
6
+ @token_endpoint: String
7
+ @pushed_authorization_request_endpoint: String
8
+ @response_types_supported: Array[String]
9
+ @grant_types_supported: Array[String]
10
+ @code_challenge_methods_supported: Array[String]
11
+ @token_endpoint_auth_methods_supported: Array[String]
12
+ @token_endpoint_auth_signing_alg_values_supported: Array[String]
13
+ @scopes_supported: Array[String]
14
+ @dpop_signing_alg_values_supported: Array[String]
15
+
16
+ REQUIRED_FIELDS: ::Array["issuer" | "authorization_endpoint" | "token_endpoint" | "response_types_supported" | "grant_types_supported" | "code_challenge_methods_supported" | "token_endpoint_auth_methods_supported" | "token_endpoint_auth_signing_alg_values_supported" | "scopes_supported" | "dpop_signing_alg_values_supported" | "pushed_authorization_request_endpoint"]
17
+
18
+ attr_reader issuer: String
19
+ attr_reader authorization_endpoint: String
20
+ attr_reader token_endpoint: String
21
+ attr_reader pushed_authorization_request_endpoint: String
22
+ attr_reader response_types_supported: Array[String]
23
+ attr_reader grant_types_supported: Array[String]
24
+ attr_reader code_challenge_methods_supported: Array[String]
25
+ attr_reader token_endpoint_auth_methods_supported: Array[String]
26
+ attr_reader token_endpoint_auth_signing_alg_values_supported: Array[String]
27
+ attr_reader scopes_supported: Array[String]
28
+ attr_reader dpop_signing_alg_values_supported: Array[String]
29
+
30
+ def initialize: (Hash[String, untyped] metadata) -> void
31
+
32
+ # Fetches and validates Authorization Server metadata from an issuer URL
33
+ # @param issuer [String] Authorization Server issuer URL
34
+ # @return [AuthorizationServer] new instance with fetched metadata
35
+ # @raise [InvalidAuthorizationServer] if metadata is invalid
36
+ def self.from_issuer: (String issuer) -> AuthorizationServer
37
+
38
+ def to_h: () -> Hash[Symbol, untyped]
39
+
40
+ private
41
+
42
+ def validate_and_set_metadata: (Hash[String, untyped] metadata) -> void
43
+
44
+ def validate_issuer: (String issuer) -> String
45
+
46
+ def validate_https_url: (String url) -> String
47
+
48
+ def validate_response_types: (Array[String] types) -> void
49
+
50
+ def validate_grant_types: (Array[String] types) -> void
51
+
52
+ def validate_code_challenge_methods: (Array[String] methods) -> void
53
+
54
+ def validate_token_endpoint_auth_methods: (Array[String] methods) -> void
55
+
56
+ def validate_token_endpoint_auth_signing_algs: (Array[String] algs) -> void
57
+
58
+ def validate_dpop_signing_algs: (Array[String] algs) -> void
59
+
60
+ def validate_scopes: (Array[String] scopes) -> void
61
+
62
+ def validate_boolean_field: (Hash[String, untyped] metadata, String field, bool required_value) -> void
63
+
64
+ private def self.fetch_metadata: (String issuer) -> http_response
65
+
66
+ private def self.parse_metadata: (String body) -> Hash[String, untyped]
67
+
68
+ private def self.validate_issuer: (String metadata_issuer, String request_issuer) -> void
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,21 @@
1
+ module AuthProto
2
+ module ServerMetadata
3
+ class OriginURL
4
+ @url: String
5
+ @uri: URI::Generic
6
+
7
+ attr_reader url: String
8
+ attr_reader uri: URI::Generic
9
+
10
+ def initialize: (String url) -> void
11
+
12
+ def valid?: () -> bool
13
+
14
+ private
15
+
16
+ def https_scheme?: () -> bool
17
+ def root_path?: () -> bool
18
+ def explicit_port?: () -> bool
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,27 @@
1
+ module AuthProto
2
+ module ServerMetadata
3
+ class ResourceServer
4
+ @authorization_servers: Array[String]
5
+
6
+ attr_reader authorization_servers: Array[String]
7
+
8
+ def initialize: (Hash[String, untyped] metadata) -> void
9
+
10
+ def self.from_url: (String url) -> ResourceServer
11
+
12
+ private
13
+
14
+ def validate_authorization_servers: (Array[String] servers) -> Array[String]
15
+
16
+ def ensure_servers_exist: (Array[String] | nil) -> void
17
+
18
+ def ensure_exactly_one_server: (Array[String]) -> void
19
+
20
+ def validate_server_url_format: (String server_url) -> void
21
+
22
+ private def self.fetch_metadata: (String url) -> http_response
23
+
24
+ private def self.parse_metadata: (String body) -> Hash[String, untyped]
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,28 @@
1
+ module AuthProto
2
+ module State
3
+ class Session
4
+ include MonitorMixin
5
+
6
+ attr_reader session_id: String
7
+ attr_reader state_token: String
8
+ attr_reader client_id: String
9
+ attr_reader scope: String
10
+ attr_reader pkce_verifier: String
11
+ attr_reader pkce_challenge: String
12
+ attr_reader auth_server: ServerMetadata::AuthorizationServer?
13
+ attr_reader did: String?
14
+ attr_reader tokens: TokenSet?
15
+
16
+ def initialize: (client_id: String, scope: String, ?auth_server: ServerMetadata::AuthorizationServer?, ?did: String?) -> void
17
+ def authorization_server=: (ServerMetadata::AuthorizationServer server) -> ServerMetadata::AuthorizationServer
18
+ def did=: (String did) -> String
19
+ def tokens=: (TokenSet tokens) -> String
20
+ def authorized?: () -> bool
21
+ def renewable?: () -> bool
22
+ def validate_state: (String? state) -> bool
23
+
24
+ private
25
+ def secure_compare: (String str1, String str2) -> bool
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,15 @@
1
+ module AuthProto
2
+ module State
3
+ class SessionManager
4
+ @serializer: Serialization::Session
5
+
6
+ def initialize: () -> void
7
+ def create_session: (client_id: String, scope: String, ?auth_server: ServerMetadata::AuthorizationServer?, ?did: String?) -> Session
8
+ def update_session: (Session session) -> Session
9
+ def get_session: (String session_id) -> Session?
10
+ def get_session_by_state: (String? state) -> Session?
11
+ def remove_session: (String session_id) -> void
12
+ def cleanup_expired: () -> void
13
+ end
14
+ end
15
+ end