Require verified domain ownership for Microsoft OIDC
Stop trusting the email on its own: set trustProviderEmail to false so email_verified is required, and additionally require the "xms_edov" claim, which Azure sets only after verifying the issuing tenant owns the email's domain. A token that lacks it is rejected before any identity is matched. Signed-off-by: Sacha Al Himdani <sacha@probo.com>
This commit is contained in:
@@ -64,6 +64,10 @@ type (
|
||||
// the email_verified claim does not need to be present in
|
||||
// the ID token.
|
||||
trustProviderEmail bool
|
||||
|
||||
// requireEmailDomainOwnerVerified requires the "xms_edov"
|
||||
// claim (nOAuth mitigation).
|
||||
requireEmailDomainOwnerVerified bool
|
||||
}
|
||||
|
||||
UserInfo struct {
|
||||
@@ -112,6 +116,9 @@ type (
|
||||
EmailVerified any `json:"email_verified"`
|
||||
Name string `json:"name"`
|
||||
HostedDomain string `json:"hd"`
|
||||
|
||||
// EmailDomainOwnerVerified is Microsoft's "xms_edov" domain-ownership claim.
|
||||
EmailDomainOwnerVerified any `json:"xms_edov"`
|
||||
}
|
||||
)
|
||||
|
||||
@@ -141,6 +148,17 @@ func (c *idTokenClaims) isEmailVerified() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *idTokenClaims) isEmailDomainOwnerVerified() bool {
|
||||
switch v := c.EmailDomainOwnerVerified.(type) {
|
||||
case bool:
|
||||
return v
|
||||
case string:
|
||||
return strings.EqualFold(v, "true")
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var (
|
||||
googleEndpoint = oauth2.Endpoint{
|
||||
AuthURL: "https://accounts.google.com/o/oauth2/v2/auth",
|
||||
@@ -208,8 +226,9 @@ func NewService(
|
||||
RedirectURL: baseURL + "/api/connect/v1/oidc/microsoft/callback",
|
||||
Scopes: []string{"openid", "email", "profile"},
|
||||
},
|
||||
jwksURL: microsoftJWKSURL,
|
||||
trustProviderEmail: true,
|
||||
jwksURL: microsoftJWKSURL,
|
||||
trustProviderEmail: false,
|
||||
requireEmailDomainOwnerVerified: true,
|
||||
issuerValidator: func(iss string) bool {
|
||||
return strings.HasPrefix(iss, "https://login.microsoftonline.com/") &&
|
||||
strings.HasSuffix(iss, "/v2.0")
|
||||
@@ -404,6 +423,10 @@ func (s *Service) HandleCallback(
|
||||
return nil, "", nil, NewEmailNotVerifiedError()
|
||||
}
|
||||
|
||||
if info.requireEmailDomainOwnerVerified && !claims.isEmailDomainOwnerVerified() {
|
||||
return nil, "", nil, NewEmailNotVerifiedError()
|
||||
}
|
||||
|
||||
if !info.enterpriseChecker(claims) {
|
||||
return nil, "", nil, NewPersonalAccountNotAllowedError()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user