Files
teleport/lib/msgraph/models.go
T

190 lines
6.6 KiB
Go

// Teleport
// Copyright (C) 2024 Gravitational, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package msgraph
import (
"encoding/json"
"slices"
"github.com/gravitational/trace"
"github.com/gravitational/teleport/lib/utils"
)
type GroupMember interface {
GetID() *string
isGroupMember()
}
type DirectoryObject struct {
ID *string `json:"id,omitempty"`
DisplayName *string `json:"displayName,omitempty"`
}
type Group struct {
DirectoryObject
// GroupTypes is a list of group type strings.
GroupTypes []string `json:"groupTypes,omitempty"`
// OnPremisesDomainName is the on-premises domain name of the group.
OnPremisesDomainName *string `json:"onPremisesDomainName,omitempty"`
// OnPremisesNetBiosName is the on-premises NetBIOS name of the group.
OnPremisesNetBiosName *string `json:"onPremisesNetBiosName,omitempty"`
// OnPremisesSamAccountName is the on-premises SAM account name of the group.
OnPremisesSamAccountName *string `json:"onPremisesSamAccountName,omitempty"`
}
func (g *Group) IsOffice365Group() bool {
const office365Group = "Unified"
return slices.Contains(g.GroupTypes, office365Group)
}
func (g *Group) isGroupMember() {}
func (g *Group) GetID() *string { return g.ID }
type User struct {
DirectoryObject
Mail *string `json:"mail,omitempty"`
OnPremisesSAMAccountName *string `json:"onPremisesSamAccountName,omitempty"`
UserPrincipalName *string `json:"userPrincipalName,omitempty"`
Surname *string `json:"surname,omitempty"`
GivenName *string `json:"givenName,omitempty"`
}
func (g *User) isGroupMember() {}
func (u *User) GetID() *string { return u.ID }
type Application struct {
DirectoryObject
AppID *string `json:"appId,omitempty"`
IdentifierURIs *[]string `json:"identifierUris,omitempty"`
Web *WebApplication `json:"web,omitempty"`
GroupMembershipClaims *string `json:"groupMembershipClaims,omitempty"`
OptionalClaims *OptionalClaims `json:"optionalClaims,omitempty"`
}
const (
// OPTIONAL_CLAIM_GROUP_NAME is the group claim.
OPTIONAL_CLAIM_GROUP_NAME = "groups"
)
const (
// OPTIONAL_CLAIM_ADDITIONAL_PROPERTIES_SAM_ACCOUNT_NAME is the sAMAccountName claim.
OPTIONAL_CLAIM_ADDITIONAL_PROPERTIES_SAM_ACCOUNT_NAME = "sam_account_name"
// OPTIONAL_CLAIM_ADDITIONAL_PROPERTIES_DNS_DOMAIN_AND_SAM_ACCOUNT_NAME is the dnsDomainName\sAMAccountName claim.
OPTIONAL_CLAIM_ADDITIONAL_PROPERTIES_DNS_DOMAIN_AND_SAM_ACCOUNT_NAME = "dns_domain_and_sam_account_name"
// OPTIONAL_CLAIM_ADDITIONAL_PROPERTIES_NETBIOS_DOMAIN_AND_SAM_ACCOUNT_NAME is the netbiosDomainName\sAMAccountName claim.
OPTIONAL_CLAIM_ADDITIONAL_PROPERTIES_NETBIOS_DOMAIN_AND_SAM_ACCOUNT_NAME = "netbios_domain_and_sam_account_name"
// OPTIONAL_CLAIM_ADDITIONAL_PROPERTIES_EMIT_AS_ROLES is the emit_as_roles claim.
OPTIONAL_CLAIM_ADDITIONAL_PROPERTIES_EMIT_AS_ROLES = "emit_as_roles"
// OPTIONAL_CLAIM_ADDITIONAL_PROPERTIES_CLOUD_DISPLAYNAME is the cloud_displayname claim.
OPTIONAL_CLAIM_ADDITIONAL_PROPERTIES_CLOUD_DISPLAYNAME = "cloud_displayname"
)
// OptionalClaim represents an optional claim in a token.
// https://learn.microsoft.com/en-us/entra/identity-platform/optional-claims?tabs=appui
type OptionalClaim struct {
// AdditionalProperties is a list of additional properties.
// Possible values:
// - sam_account_name: sAMAccountName
// - dns_domain_and_sam_account_name: dnsDomainName\sAMAccountName
// - netbios_domain_and_sam_account_name: netbiosDomainName\sAMAccountName
// - emit_as_roles
// - cloud_displayname
AdditionalProperties []string `json:"additionalProperties,omitempty"`
Essential *bool `json:"essential,omitempty"`
Name *string `json:"name,omitempty"`
Source *string `json:"source,omitempty"`
}
// OptionalClaims represents optional claims in a token.
type OptionalClaims struct {
IDToken []OptionalClaim `json:"idToken,omitempty"`
AccessToken []OptionalClaim `json:"accessToken,omitempty"`
SAML2Token []OptionalClaim `json:"saml2Token,omitempty"`
}
type WebApplication struct {
RedirectURIs *[]string `json:"redirectUris,omitempty"`
}
type ServicePrincipal struct {
DirectoryObject
AppRoleAssignmentRequired *bool `json:"appRoleAssignmentRequired,omitempty"`
PreferredSingleSignOnMode *string `json:"preferredSingleSignOnMode,omitempty"`
PreferredTokenSigningKeyThumbprint *string `json:"preferredTokenSigningKeyThumbprint,omitempty"`
AppRoles []*AppRole `json:"appRoles,omitempty"`
}
type ApplicationServicePrincipal struct {
Application *Application `json:"application,omitempty"`
ServicePrincipal *ServicePrincipal `json:"servicePrincipal,omitempty"`
}
type FederatedIdentityCredential struct {
Audiences *[]string `json:"audiences,omitempty"`
Issuer *string `json:"issuer,omitempty"`
Name *string `json:"name,omitempty"`
Subject *string `json:"subject,omitempty"`
}
type SelfSignedCertificate struct {
Thumbprint *string `json:"thumbprint,omitempty"`
}
type AppRole struct {
ID *string `json:"id,omitempty"`
Value *string `json:"value,omitempty"`
}
type AppRoleAssignment struct {
ID *string `json:"id,omitempty"`
AppRoleID *string `json:"appRoleId,omitempty"`
PrincipalID *string `json:"principalId,omitempty"`
ResourceID *string `json:"resourceId,omitempty"`
}
func decodeGroupMember(msg json.RawMessage) (GroupMember, error) {
var temp struct {
Type string `json:"@odata.type"`
}
if err := utils.FastUnmarshal(msg, &temp); err != nil {
return nil, trace.Wrap(err)
}
var err error
var member GroupMember
switch temp.Type {
case "#microsoft.graph.user":
var u *User
err = utils.FastUnmarshal(msg, &u)
member = u
case "#microsoft.graph.group":
var g *Group
err = utils.FastUnmarshal(msg, &g)
member = g
default:
// Return an error if we encounter a type we do not support.
// The caller ignores the error and continues processing the next entry.
err = &unsupportedGroupMember{Type: temp.Type}
}
return member, trace.Wrap(err)
}