github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/mfa/prompt.go (about) 1 /* 2 Copyright 2023 Gravitational, Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package mfa 18 19 import ( 20 "context" 21 "fmt" 22 23 "github.com/gravitational/teleport/api/client/proto" 24 ) 25 26 // Prompt is an MFA prompt. 27 type Prompt interface { 28 // Run prompts the user to complete an MFA authentication challenge. 29 Run(ctx context.Context, chal *proto.MFAAuthenticateChallenge) (*proto.MFAAuthenticateResponse, error) 30 } 31 32 // PromptFunc is a function wrapper that implements the Prompt interface. 33 type PromptFunc func(ctx context.Context, chal *proto.MFAAuthenticateChallenge) (*proto.MFAAuthenticateResponse, error) 34 35 // Run prompts the user to complete an MFA authentication challenge. 36 func (f PromptFunc) Run(ctx context.Context, chal *proto.MFAAuthenticateChallenge) (*proto.MFAAuthenticateResponse, error) { 37 return f(ctx, chal) 38 } 39 40 // PromptConstructor is a function that creates a new MFA prompt. 41 type PromptConstructor func(...PromptOpt) Prompt 42 43 // PromptConfig contains common mfa prompt config options. 44 type PromptConfig struct { 45 // PromptReason is an optional message to share with the user before an MFA Prompt. 46 // It is intended to provide context about why the user is being prompted where it may 47 // not be obvious, such as for admin actions or per-session MFA. 48 PromptReason string 49 // DeviceType is an optional device description to emphasize during the prompt. 50 DeviceType DeviceDescriptor 51 // Quiet suppresses users prompts. 52 Quiet bool 53 } 54 55 // DeviceDescriptor is a descriptor for a device, such as "registered". 56 type DeviceDescriptor string 57 58 // DeviceDescriptorRegistered is a registered device. 59 const DeviceDescriptorRegistered = "registered" 60 61 // PromptOpt applies configuration options to a prompt. 62 type PromptOpt func(*PromptConfig) 63 64 // WithQuiet sets the prompt's Quiet field. 65 func WithQuiet() PromptOpt { 66 return func(cfg *PromptConfig) { 67 cfg.Quiet = true 68 } 69 } 70 71 // WithPromptReason sets the prompt's PromptReason field. 72 func WithPromptReason(hint string) PromptOpt { 73 return func(cfg *PromptConfig) { 74 cfg.PromptReason = hint 75 } 76 } 77 78 // WithPromptReasonAdminAction sets the prompt's PromptReason field to a standard admin action message. 79 func WithPromptReasonAdminAction() PromptOpt { 80 const adminMFAPromptReason = "This is an admin-level action and requires MFA to complete" 81 return WithPromptReason(adminMFAPromptReason) 82 } 83 84 // WithPromptReasonSessionMFA sets the prompt's PromptReason field to a standard session mfa message. 85 func WithPromptReasonSessionMFA(serviceType, serviceName string) PromptOpt { 86 return WithPromptReason(fmt.Sprintf("MFA is required to access %s %q", serviceType, serviceName)) 87 } 88 89 // WithPromptDeviceType sets the prompt's DeviceType field. 90 func WithPromptDeviceType(deviceType DeviceDescriptor) PromptOpt { 91 return func(cfg *PromptConfig) { 92 cfg.DeviceType = deviceType 93 } 94 }