Module: Legion::API::Routes::Auth
- Defined in:
- lib/legion/api/auth.rb
Class Method Summary collapse
-
.register_token_exchange(app) ⇒ Object
rubocop:disable Metrics/MethodLength.
- .registered(app) ⇒ Object
Class Method Details
.register_token_exchange(app) ⇒ Object
rubocop:disable Metrics/MethodLength
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/legion/api/auth.rb', line 11 def self.register_token_exchange(app) # rubocop:disable Metrics/MethodLength app.post '/api/auth/token' do Legion::Logging.debug "API: POST /api/auth/token params=#{params.keys}" body = parse_request_body grant_type = body[:grant_type] subject_token = body[:subject_token] unless grant_type == 'urn:ietf:params:oauth:grant-type:token-exchange' Legion::Logging.warn "API POST /api/auth/token returned 400: unsupported grant_type=#{grant_type}" halt 400, json_error('unsupported_grant_type', 'expected urn:ietf:params:oauth:grant-type:token-exchange', status_code: 400) end unless subject_token Legion::Logging.warn 'API POST /api/auth/token returned 400: subject_token is required' halt 400, json_error('missing_subject_token', 'subject_token is required', status_code: 400) end unless defined?(Legion::Crypt::JWT) && Legion::Crypt::JWT.respond_to?(:verify_with_jwks) halt 501, json_error('jwks_validation_not_available', 'legion-crypt JWKS support not loaded', status_code: 501) end rbac_settings = (Legion::Settings[:rbac].is_a?(Hash) && Legion::Settings[:rbac][:entra]) || {} tenant_id = rbac_settings[:tenant_id] unless tenant_id Legion::Logging.error 'API POST /api/auth/token returned 500: rbac.entra.tenant_id not set' halt 500, json_error('entra_tenant_not_configured', 'rbac.entra.tenant_id not set', status_code: 500) end jwks_url = "https://login.microsoftonline.com/#{tenant_id}/discovery/v2.0/keys" issuer = "https://login.microsoftonline.com/#{tenant_id}/v2.0" begin entra_claims = Legion::Crypt::JWT.verify_with_jwks( subject_token, jwks_url: jwks_url, issuers: [issuer] ) rescue Legion::Crypt::JWT::ExpiredTokenError Legion::Logging.warn 'API POST /api/auth/token returned 401: Entra token has expired' halt 401, json_error('token_expired', 'Entra token has expired', status_code: 401) rescue Legion::Crypt::JWT::InvalidTokenError => e Legion::Logging.warn "API POST /api/auth/token returned 401: #{e.}" halt 401, json_error('invalid_token', e., status_code: 401) rescue Legion::Crypt::JWT::Error => e Legion::Logging.error "API POST /api/auth/token returned 502: #{e.}" halt 502, json_error('identity_provider_unavailable', e., status_code: 502) end unless defined?(Legion::Rbac::EntraClaimsMapper) halt 501, json_error('claims_mapper_not_available', 'legion-rbac EntraClaimsMapper not loaded', status_code: 501) end mapped = Legion::Rbac::EntraClaimsMapper.map_claims( entra_claims, role_map: rbac_settings[:role_map] || Legion::Rbac::EntraClaimsMapper::DEFAULT_ROLE_MAP, group_map: rbac_settings[:group_map] || {}, default_role: rbac_settings[:default_role] || 'worker' ) ttl = 28_800 token = Legion::API::Token.issue_human_token( msid: mapped[:sub], name: mapped[:name], roles: mapped[:roles], ttl: ttl ) Legion::Logging.info "API: issued human token for sub=#{mapped[:sub]} roles=#{mapped[:roles]&.join(',')}" json_response({ access_token: token, token_type: 'Bearer', expires_in: ttl, roles: mapped[:roles], team: mapped[:team] }) end end |
.registered(app) ⇒ Object
7 8 9 |
# File 'lib/legion/api/auth.rb', line 7 def self.registered(app) register_token_exchange(app) end |