Module: Legion::Gaia::Channels::Teams::BotFrameworkAuth
- Extended by:
- Logging::Helper
- Defined in:
- lib/legion/gaia/channels/teams/bot_framework_auth.rb
Constant Summary collapse
- OPENID_METADATA_URL =
'https://login.botframework.com/v1/.well-known/openidconfiguration'- BOT_FRAMEWORK_ISSUER =
'https://api.botframework.com'- EMULATOR_ISSUER =
'https://sts.windows.net/d6d49420-f39b-4df7-a1dc-d59a935871db/'- JWKS_CACHE_TTL =
3600
Class Method Summary collapse
- .check_expiry(payload) ⇒ Object
- .check_issuer(payload, _allow_emulator) ⇒ Object
- .decode_jwt_segment(segment) ⇒ Object
- .extract_identity(activity) ⇒ Object
- .issuer_valid?(payload, allow_emulator) ⇒ Boolean
- .token_time_valid?(payload) ⇒ Boolean
- .validate_claims(payload, app_id:, allow_emulator: false) ⇒ Object
- .validate_token(token, app_id:, allow_emulator: false) ⇒ Object
Class Method Details
.check_expiry(payload) ⇒ Object
84 85 86 87 88 89 |
# File 'lib/legion/gaia/channels/teams/bot_framework_auth.rb', line 84 def check_expiry(payload) now = Time.now.to_i return { valid: false, error: :token_expired } if payload['exp'] && payload['exp'].to_i < now { valid: false, error: :token_not_yet_valid } end |
.check_issuer(payload, _allow_emulator) ⇒ Object
98 99 100 |
# File 'lib/legion/gaia/channels/teams/bot_framework_auth.rb', line 98 def check_issuer(payload, _allow_emulator) { valid: false, error: :invalid_issuer, issuer: payload['iss'] } end |
.decode_jwt_segment(segment) ⇒ Object
66 67 68 69 70 71 72 73 74 |
# File 'lib/legion/gaia/channels/teams/bot_framework_auth.rb', line 66 def decode_jwt_segment(segment) remainder = segment.length % 4 padded = remainder.zero? ? segment : segment + ('=' * (4 - remainder)) decoded = Base64.urlsafe_decode64(padded) ::JSON.parse(decoded) rescue StandardError => e handle_exception(e, level: :debug, operation: 'gaia.channels.teams.bot_framework_auth.decode_jwt_segment') nil end |
.extract_identity(activity) ⇒ Object
55 56 57 58 59 60 61 62 63 64 |
# File 'lib/legion/gaia/channels/teams/bot_framework_auth.rb', line 55 def extract_identity(activity) from = activity['from'] || activity[:from] || {} { aad_object_id: from['aadObjectId'] || from[:aadObjectId], user_id: from['id'] || from[:id], user_name: from['name'] || from[:name], tenant_id: activity.dig('channelData', 'tenant', 'id') || activity.dig(:channelData, :tenant, :id) } end |
.issuer_valid?(payload, allow_emulator) ⇒ Boolean
91 92 93 94 95 96 |
# File 'lib/legion/gaia/channels/teams/bot_framework_auth.rb', line 91 def issuer_valid?(payload, allow_emulator) issuer = payload['iss'] valid_issuers = [BOT_FRAMEWORK_ISSUER] valid_issuers << EMULATOR_ISSUER if allow_emulator valid_issuers.any? { |i| issuer&.start_with?(i) || issuer == i } end |
.token_time_valid?(payload) ⇒ Boolean
76 77 78 79 80 81 82 |
# File 'lib/legion/gaia/channels/teams/bot_framework_auth.rb', line 76 def token_time_valid?(payload) now = Time.now.to_i return false if payload['exp'] && payload['exp'].to_i < now return false if payload['nbf'] && payload['nbf'].to_i > now + 300 true end |
.validate_claims(payload, app_id:, allow_emulator: false) ⇒ Object
47 48 49 50 51 52 53 |
# File 'lib/legion/gaia/channels/teams/bot_framework_auth.rb', line 47 def validate_claims(payload, app_id:, allow_emulator: false) return check_expiry(payload) unless token_time_valid?(payload) return check_issuer(payload, allow_emulator) unless issuer_valid?(payload, allow_emulator) return { valid: false, error: :invalid_audience, audience: payload['aud'] } unless payload['aud'] == app_id { valid: true } end |
.validate_token(token, app_id:, allow_emulator: false) ⇒ Object
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/legion/gaia/channels/teams/bot_framework_auth.rb', line 23 def validate_token(token, app_id:, allow_emulator: false) return { valid: false, error: :missing_token } if token.nil? || token.empty? parts = token.split('.') return { valid: false, error: :malformed_jwt } unless parts.size == 3 header = decode_jwt_segment(parts[0]) payload = decode_jwt_segment(parts[1]) return { valid: false, error: :decode_failed } unless header && payload validation = validate_claims(payload, app_id: app_id, allow_emulator: allow_emulator) return validation unless validation[:valid] { valid: true, claims: payload, entra_oid: payload['oid'], app_id: payload['appid'] || payload['azp'], tenant_id: payload['tid'], service_url: payload['serviceurl'] } end |