summaryrefslogtreecommitdiff
path: root/internal/authorization/amr.go
blob: c71b6974074c85e190db3db019e642979ed37617 (plain)
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
122
123
package authorization

func NewAuthenticationMethodsReferencesFromClaim(claim []string) (amr AuthenticationMethodsReferences) {
	for _, ref := range claim {
		switch ref {
		case AMRKnowledgeBasedAuthentication:
			amr.KnowledgeBasedAuthentication = true
		case AMRPasswordBasedAuthentication:
			amr.UsernameAndPassword = true
		case AMROneTimePassword:
			amr.TOTP = true
		case AMRShortMessageService:
			amr.Duo = true
		case AMRProofOfPossession:
			amr.WebAuthn = true
		case AMRHardwareSecuredKey:
			amr.WebAuthn = true
			amr.WebAuthnHardware = true
		case AMRSoftwareSecuredKey:
			amr.WebAuthn = true
			amr.WebAuthnSoftware = true
		case AMRUserPresence:
			amr.WebAuthnUserVerified = true
		}
	}

	return amr
}

// AuthenticationMethodsReferences holds AMR information.
type AuthenticationMethodsReferences struct {
	KnowledgeBasedAuthentication bool
	UsernameAndPassword          bool
	TOTP                         bool
	Duo                          bool
	WebAuthn                     bool
	WebAuthnHardware             bool
	WebAuthnSoftware             bool
	WebAuthnUserPresence         bool
	WebAuthnUserVerified         bool
}

// FactorKnowledge returns true if a "something you know" factor of authentication was used.
func (r AuthenticationMethodsReferences) FactorKnowledge() bool {
	return r.UsernameAndPassword || r.KnowledgeBasedAuthentication
}

// FactorPossession returns true if a "something you have" factor of authentication was used.
func (r AuthenticationMethodsReferences) FactorPossession() bool {
	return r.TOTP || r.Duo || r.WebAuthn || r.WebAuthnHardware || r.WebAuthnSoftware
}

// MultiFactorAuthentication returns true if multiple factors were used.
func (r AuthenticationMethodsReferences) MultiFactorAuthentication() bool {
	return r.FactorKnowledge() && r.FactorPossession()
}

// ChannelBrowser returns true if a browser was used to authenticate.
func (r AuthenticationMethodsReferences) ChannelBrowser() bool {
	return r.UsernameAndPassword || r.TOTP || r.WebAuthn || r.WebAuthnHardware || r.WebAuthnSoftware
}

// ChannelService returns true if a non-browser service was used to authenticate.
func (r AuthenticationMethodsReferences) ChannelService() bool {
	return r.Duo
}

// MultiChannelAuthentication returns true if the user used more than one channel to authenticate.
func (r AuthenticationMethodsReferences) MultiChannelAuthentication() bool {
	return r.ChannelBrowser() && r.ChannelService()
}

// MarshalRFC8176 returns the AMR claim slice of strings in the RFC8176 format.
// https://datatracker.ietf.org/doc/html/rfc8176
func (r AuthenticationMethodsReferences) MarshalRFC8176() []string {
	var amr []string

	if r.UsernameAndPassword {
		amr = append(amr, AMRPasswordBasedAuthentication)
	}

	if r.KnowledgeBasedAuthentication {
		amr = append(amr, AMRKnowledgeBasedAuthentication)
	}

	if r.TOTP {
		amr = append(amr, AMROneTimePassword)
	}

	if r.Duo {
		amr = append(amr, AMRShortMessageService)
	}

	if r.WebAuthn || r.WebAuthnHardware || r.WebAuthnSoftware {
		amr = append(amr, AMRProofOfPossession)
	}

	if r.WebAuthnHardware {
		amr = append(amr, AMRHardwareSecuredKey)
	}

	if r.WebAuthnSoftware {
		amr = append(amr, AMRSoftwareSecuredKey)
	}

	if r.WebAuthnUserPresence {
		amr = append(amr, AMRUserPresence)
	}

	if r.WebAuthnUserVerified {
		amr = append(amr, AMRPersonalIdentificationNumber)
	}

	if r.MultiFactorAuthentication() {
		amr = append(amr, AMRMultiFactorAuthentication)
	}

	if r.MultiChannelAuthentication() {
		amr = append(amr, AMRMultiChannelAuthentication)
	}

	return amr
}