315 lines
8.3 KiB
Go
315 lines
8.3 KiB
Go
|
// Package credentials provides credentials management for Kerberos 5 authentication.
|
||
|
package credentials
|
||
|
|
||
|
import (
|
||
|
"time"
|
||
|
|
||
|
"github.com/hashicorp/go-uuid"
|
||
|
"gopkg.in/jcmturner/gokrb5.v7/iana/nametype"
|
||
|
"gopkg.in/jcmturner/gokrb5.v7/keytab"
|
||
|
"gopkg.in/jcmturner/gokrb5.v7/types"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
// AttributeKeyADCredentials assigned number for AD credentials.
|
||
|
AttributeKeyADCredentials = "gokrb5AttributeKeyADCredentials"
|
||
|
)
|
||
|
|
||
|
// Credentials struct for a user.
|
||
|
// Contains either a keytab, password or both.
|
||
|
// Keytabs are used over passwords if both are defined.
|
||
|
type Credentials struct {
|
||
|
username string
|
||
|
displayName string
|
||
|
realm string
|
||
|
cname types.PrincipalName
|
||
|
keytab *keytab.Keytab
|
||
|
password string
|
||
|
attributes map[string]interface{}
|
||
|
validUntil time.Time
|
||
|
|
||
|
authenticated bool
|
||
|
human bool
|
||
|
authTime time.Time
|
||
|
groupMembership map[string]bool
|
||
|
sessionID string
|
||
|
}
|
||
|
|
||
|
// ADCredentials contains information obtained from the PAC.
|
||
|
type ADCredentials struct {
|
||
|
EffectiveName string
|
||
|
FullName string
|
||
|
UserID int
|
||
|
PrimaryGroupID int
|
||
|
LogOnTime time.Time
|
||
|
LogOffTime time.Time
|
||
|
PasswordLastSet time.Time
|
||
|
GroupMembershipSIDs []string
|
||
|
LogonDomainName string
|
||
|
LogonDomainID string
|
||
|
LogonServer string
|
||
|
}
|
||
|
|
||
|
// New creates a new Credentials instance.
|
||
|
func New(username string, realm string) *Credentials {
|
||
|
uid, err := uuid.GenerateUUID()
|
||
|
if err != nil {
|
||
|
uid = "00unique-sess-ions-uuid-unavailable0"
|
||
|
}
|
||
|
return &Credentials{
|
||
|
username: username,
|
||
|
displayName: username,
|
||
|
realm: realm,
|
||
|
cname: types.NewPrincipalName(nametype.KRB_NT_PRINCIPAL, username),
|
||
|
keytab: keytab.New(),
|
||
|
attributes: make(map[string]interface{}),
|
||
|
groupMembership: make(map[string]bool),
|
||
|
sessionID: uid,
|
||
|
human: true,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// NewFromPrincipalName creates a new Credentials instance with the user details provides as a PrincipalName type.
|
||
|
func NewFromPrincipalName(cname types.PrincipalName, realm string) *Credentials {
|
||
|
uid, err := uuid.GenerateUUID()
|
||
|
if err != nil {
|
||
|
uid = "00unique-sess-ions-uuid-unavailable0"
|
||
|
}
|
||
|
return &Credentials{
|
||
|
username: cname.PrincipalNameString(),
|
||
|
displayName: cname.PrincipalNameString(),
|
||
|
realm: realm,
|
||
|
cname: cname,
|
||
|
keytab: keytab.New(),
|
||
|
attributes: make(map[string]interface{}),
|
||
|
groupMembership: make(map[string]bool),
|
||
|
sessionID: uid,
|
||
|
human: true,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// WithKeytab sets the Keytab in the Credentials struct.
|
||
|
func (c *Credentials) WithKeytab(kt *keytab.Keytab) *Credentials {
|
||
|
c.keytab = kt
|
||
|
c.password = ""
|
||
|
return c
|
||
|
}
|
||
|
|
||
|
// Keytab returns the credential's Keytab.
|
||
|
func (c *Credentials) Keytab() *keytab.Keytab {
|
||
|
return c.keytab
|
||
|
}
|
||
|
|
||
|
// HasKeytab queries if the Credentials has a keytab defined.
|
||
|
func (c *Credentials) HasKeytab() bool {
|
||
|
if c.keytab != nil && len(c.keytab.Entries) > 0 {
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// WithPassword sets the password in the Credentials struct.
|
||
|
func (c *Credentials) WithPassword(password string) *Credentials {
|
||
|
c.password = password
|
||
|
c.keytab = keytab.New() // clear any keytab
|
||
|
return c
|
||
|
}
|
||
|
|
||
|
// Password returns the credential's password.
|
||
|
func (c *Credentials) Password() string {
|
||
|
return c.password
|
||
|
}
|
||
|
|
||
|
// HasPassword queries if the Credentials has a password defined.
|
||
|
func (c *Credentials) HasPassword() bool {
|
||
|
if c.password != "" {
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// SetValidUntil sets the expiry time of the credentials
|
||
|
func (c *Credentials) SetValidUntil(t time.Time) {
|
||
|
c.validUntil = t
|
||
|
}
|
||
|
|
||
|
// SetADCredentials adds ADCredentials attributes to the credentials
|
||
|
func (c *Credentials) SetADCredentials(a ADCredentials) {
|
||
|
c.SetAttribute(AttributeKeyADCredentials, a)
|
||
|
if a.FullName != "" {
|
||
|
c.SetDisplayName(a.FullName)
|
||
|
}
|
||
|
if a.EffectiveName != "" {
|
||
|
c.SetUserName(a.EffectiveName)
|
||
|
}
|
||
|
for i := range a.GroupMembershipSIDs {
|
||
|
c.AddAuthzAttribute(a.GroupMembershipSIDs[i])
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Methods to implement goidentity.Identity interface
|
||
|
|
||
|
// UserName returns the credential's username.
|
||
|
func (c *Credentials) UserName() string {
|
||
|
return c.username
|
||
|
}
|
||
|
|
||
|
// SetUserName sets the username value on the credential.
|
||
|
func (c *Credentials) SetUserName(s string) {
|
||
|
c.username = s
|
||
|
}
|
||
|
|
||
|
// CName returns the credential's client principal name.
|
||
|
func (c *Credentials) CName() types.PrincipalName {
|
||
|
return c.cname
|
||
|
}
|
||
|
|
||
|
// SetCName sets the client principal name on the credential.
|
||
|
func (c *Credentials) SetCName(pn types.PrincipalName) {
|
||
|
c.cname = pn
|
||
|
}
|
||
|
|
||
|
// Domain returns the credential's domain.
|
||
|
func (c *Credentials) Domain() string {
|
||
|
return c.realm
|
||
|
}
|
||
|
|
||
|
// SetDomain sets the domain value on the credential.
|
||
|
func (c *Credentials) SetDomain(s string) {
|
||
|
c.realm = s
|
||
|
}
|
||
|
|
||
|
// Realm returns the credential's realm. Same as the domain.
|
||
|
func (c *Credentials) Realm() string {
|
||
|
return c.Domain()
|
||
|
}
|
||
|
|
||
|
// SetRealm sets the realm value on the credential. Same as the domain
|
||
|
func (c *Credentials) SetRealm(s string) {
|
||
|
c.SetDomain(s)
|
||
|
}
|
||
|
|
||
|
// DisplayName returns the credential's display name.
|
||
|
func (c *Credentials) DisplayName() string {
|
||
|
return c.displayName
|
||
|
}
|
||
|
|
||
|
// SetDisplayName sets the display name value on the credential.
|
||
|
func (c *Credentials) SetDisplayName(s string) {
|
||
|
c.displayName = s
|
||
|
}
|
||
|
|
||
|
// Human returns if the credential represents a human or not.
|
||
|
func (c *Credentials) Human() bool {
|
||
|
return c.human
|
||
|
}
|
||
|
|
||
|
// SetHuman sets the credential as human.
|
||
|
func (c *Credentials) SetHuman(b bool) {
|
||
|
c.human = b
|
||
|
}
|
||
|
|
||
|
// AuthTime returns the time the credential was authenticated.
|
||
|
func (c *Credentials) AuthTime() time.Time {
|
||
|
return c.authTime
|
||
|
}
|
||
|
|
||
|
// SetAuthTime sets the time the credential was authenticated.
|
||
|
func (c *Credentials) SetAuthTime(t time.Time) {
|
||
|
c.authTime = t
|
||
|
}
|
||
|
|
||
|
// AuthzAttributes returns the credentials authorizing attributes.
|
||
|
func (c *Credentials) AuthzAttributes() []string {
|
||
|
s := make([]string, len(c.groupMembership))
|
||
|
i := 0
|
||
|
for a := range c.groupMembership {
|
||
|
s[i] = a
|
||
|
i++
|
||
|
}
|
||
|
return s
|
||
|
}
|
||
|
|
||
|
// Authenticated indicates if the credential has been successfully authenticated or not.
|
||
|
func (c *Credentials) Authenticated() bool {
|
||
|
return c.authenticated
|
||
|
}
|
||
|
|
||
|
// SetAuthenticated sets the credential as having been successfully authenticated.
|
||
|
func (c *Credentials) SetAuthenticated(b bool) {
|
||
|
c.authenticated = b
|
||
|
}
|
||
|
|
||
|
// AddAuthzAttribute adds an authorization attribute to the credential.
|
||
|
func (c *Credentials) AddAuthzAttribute(a string) {
|
||
|
c.groupMembership[a] = true
|
||
|
}
|
||
|
|
||
|
// RemoveAuthzAttribute removes an authorization attribute from the credential.
|
||
|
func (c *Credentials) RemoveAuthzAttribute(a string) {
|
||
|
if _, ok := c.groupMembership[a]; !ok {
|
||
|
return
|
||
|
}
|
||
|
delete(c.groupMembership, a)
|
||
|
}
|
||
|
|
||
|
// EnableAuthzAttribute toggles an authorization attribute to an enabled state on the credential.
|
||
|
func (c *Credentials) EnableAuthzAttribute(a string) {
|
||
|
if enabled, ok := c.groupMembership[a]; ok && !enabled {
|
||
|
c.groupMembership[a] = true
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// DisableAuthzAttribute toggles an authorization attribute to a disabled state on the credential.
|
||
|
func (c *Credentials) DisableAuthzAttribute(a string) {
|
||
|
if enabled, ok := c.groupMembership[a]; ok && enabled {
|
||
|
c.groupMembership[a] = false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Authorized indicates if the credential has the specified authorizing attribute.
|
||
|
func (c *Credentials) Authorized(a string) bool {
|
||
|
if enabled, ok := c.groupMembership[a]; ok && enabled {
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// SessionID returns the credential's session ID.
|
||
|
func (c *Credentials) SessionID() string {
|
||
|
return c.sessionID
|
||
|
}
|
||
|
|
||
|
// Expired indicates if the credential has expired.
|
||
|
func (c *Credentials) Expired() bool {
|
||
|
if !c.validUntil.IsZero() && time.Now().UTC().After(c.validUntil) {
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
// ValidUntil returns the credential's valid until date
|
||
|
func (c *Credentials) ValidUntil() time.Time {
|
||
|
return c.validUntil
|
||
|
}
|
||
|
|
||
|
// Attributes returns the Credentials' attributes map.
|
||
|
func (c *Credentials) Attributes() map[string]interface{} {
|
||
|
return c.attributes
|
||
|
}
|
||
|
|
||
|
// SetAttribute sets the value of an attribute.
|
||
|
func (c *Credentials) SetAttribute(k string, v interface{}) {
|
||
|
c.attributes[k] = v
|
||
|
}
|
||
|
|
||
|
// SetAttributes replaces the attributes map with the one provided.
|
||
|
func (c *Credentials) SetAttributes(a map[string]interface{}) {
|
||
|
c.attributes = a
|
||
|
}
|
||
|
|
||
|
// RemoveAttribute deletes an attribute from the attribute map that has the key provided.
|
||
|
func (c *Credentials) RemoveAttribute(k string) {
|
||
|
delete(c.attributes, k)
|
||
|
}
|