-
Notifications
You must be signed in to change notification settings - Fork 27
/
utils_authn.go
121 lines (109 loc) · 3.57 KB
/
utils_authn.go
1
2
3
4
5
6
7
8
9
10
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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package nodes
import (
"github.com/authgear/authgear-server/pkg/api/apierrors"
"github.com/authgear/authgear-server/pkg/api/model"
"github.com/authgear/authgear-server/pkg/lib/authn"
"github.com/authgear/authgear-server/pkg/lib/authn/authenticator"
"github.com/authgear/authgear-server/pkg/lib/authn/otp"
"github.com/authgear/authgear-server/pkg/lib/feature"
"github.com/authgear/authgear-server/pkg/lib/interaction"
"github.com/authgear/authgear-server/pkg/lib/ratelimit"
)
type SendOOBCodeResult struct {
Target string
Channel string
CodeLength int
}
type SendOOBCode struct {
Context *interaction.Context
Stage authn.AuthenticationStage
IsAuthenticating bool
AuthenticatorInfo *authenticator.Info
IgnoreRatelimitError bool
OTPForm otp.Form
}
func (p *SendOOBCode) Do() (*SendOOBCodeResult, error) {
var messageType otp.MessageType
switch p.Stage {
case authn.AuthenticationStagePrimary:
if p.IsAuthenticating {
messageType = otp.MessageTypeAuthenticatePrimaryOOB
} else {
messageType = otp.MessageTypeSetupPrimaryOOB
}
case authn.AuthenticationStageSecondary:
if p.IsAuthenticating {
messageType = otp.MessageTypeAuthenticateSecondaryOOB
} else {
messageType = otp.MessageTypeSetupSecondaryOOB
}
default:
panic("interaction: unknown authentication stage: " + p.Stage)
}
var channel model.AuthenticatorOOBChannel
var target string
switch p.AuthenticatorInfo.Type {
case model.AuthenticatorTypeOOBSMS:
channel = model.AuthenticatorOOBChannelSMS
target = p.AuthenticatorInfo.OOBOTP.Phone
case model.AuthenticatorTypeOOBEmail:
channel = model.AuthenticatorOOBChannelEmail
target = p.AuthenticatorInfo.OOBOTP.Email
default:
panic("interaction: incompatible authenticator type for sending oob code: " + p.AuthenticatorInfo.Type)
}
// check for feature disabled
if p.AuthenticatorInfo.Type == model.AuthenticatorTypeOOBSMS {
fc := p.Context.FeatureConfig
switch p.Stage {
case authn.AuthenticationStagePrimary:
if fc.Identity.LoginID.Types.Phone.Disabled {
return nil, feature.ErrFeatureDisabledSendingSMS
}
case authn.AuthenticationStageSecondary:
if fc.Authentication.SecondaryAuthenticators.OOBOTPSMS.Disabled {
return nil, feature.ErrFeatureDisabledSendingSMS
}
}
}
result := &SendOOBCodeResult{
Channel: string(channel),
Target: target,
CodeLength: p.OTPForm.CodeLength(),
}
msg, err := p.Context.OTPSender.Prepare(channel, p.AuthenticatorInfo.OOBOTP.ToTarget(), p.OTPForm, messageType)
if p.IgnoreRatelimitError && apierrors.IsKind(err, ratelimit.RateLimited) {
// Ignore the rate limit error and do NOT send the code.
return result, nil
} else if err != nil {
return nil, err
}
defer msg.Close()
code, err := p.Context.OTPCodeService.GenerateOTP(
otp.KindOOBOTP(p.Context.Config, channel),
p.AuthenticatorInfo.OOBOTP.ToTarget(),
p.OTPForm,
&otp.GenerateOptions{WebSessionID: p.Context.WebSessionID},
)
if p.IgnoreRatelimitError && apierrors.IsKind(err, ratelimit.RateLimited) {
// Ignore the rate limit error and do NOT send the code.
return result, nil
} else if err != nil {
return nil, err
}
err = p.Context.OTPSender.Send(msg, otp.SendOptions{OTP: code})
if err != nil {
return nil, err
}
return result, nil
}
func stageToAuthenticatorKind(stage authn.AuthenticationStage) authenticator.Kind {
switch stage {
case authn.AuthenticationStagePrimary:
return authenticator.KindPrimary
case authn.AuthenticationStageSecondary:
return authenticator.KindSecondary
default:
panic("interaction: unknown stage: " + stage)
}
}