package credentials
import (
"bytes"
"encoding/gob"
"encoding/json"
"time"
"github.com/hashicorp/go-uuid"
"github.com/jcmturner/gokrb5/v8/iana/nametype"
"github.com/jcmturner/gokrb5/v8/keytab"
"github.com/jcmturner/gokrb5/v8/types"
)
const (
AttributeKeyADCredentials = "gokrb5AttributeKeyADCredentials"
)
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
}
type marshalCredentials struct {
Username string
DisplayName string
Realm string
CName types .PrincipalName `json:"-"`
Keytab bool
Password bool
Attributes map [string ]interface {} `json:"-"`
ValidUntil time .Time
Authenticated bool
Human bool
AuthTime time .Time
GroupMembership map [string ]bool `json:"-"`
SessionID string
}
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
}
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 ,
}
}
func NewFromPrincipalName (cname types .PrincipalName , realm string ) *Credentials {
c := New (cname .PrincipalNameString (), realm )
c .cname = cname
return c
}
func (c *Credentials ) WithKeytab (kt *keytab .Keytab ) *Credentials {
c .keytab = kt
c .password = ""
return c
}
func (c *Credentials ) Keytab () *keytab .Keytab {
return c .keytab
}
func (c *Credentials ) HasKeytab () bool {
if c .keytab != nil && len (c .keytab .Entries ) > 0 {
return true
}
return false
}
func (c *Credentials ) WithPassword (password string ) *Credentials {
c .password = password
c .keytab = keytab .New ()
return c
}
func (c *Credentials ) Password () string {
return c .password
}
func (c *Credentials ) HasPassword () bool {
if c .password != "" {
return true
}
return false
}
func (c *Credentials ) SetValidUntil (t time .Time ) {
c .validUntil = t
}
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 ])
}
}
func (c *Credentials ) GetADCredentials () ADCredentials {
if a , ok := c .attributes [AttributeKeyADCredentials ].(ADCredentials ); ok {
return a
}
return ADCredentials {}
}
func (c *Credentials ) UserName () string {
return c .username
}
func (c *Credentials ) SetUserName (s string ) {
c .username = s
}
func (c *Credentials ) CName () types .PrincipalName {
return c .cname
}
func (c *Credentials ) SetCName (pn types .PrincipalName ) {
c .cname = pn
}
func (c *Credentials ) Domain () string {
return c .realm
}
func (c *Credentials ) SetDomain (s string ) {
c .realm = s
}
func (c *Credentials ) Realm () string {
return c .Domain ()
}
func (c *Credentials ) SetRealm (s string ) {
c .SetDomain (s )
}
func (c *Credentials ) DisplayName () string {
return c .displayName
}
func (c *Credentials ) SetDisplayName (s string ) {
c .displayName = s
}
func (c *Credentials ) Human () bool {
return c .human
}
func (c *Credentials ) SetHuman (b bool ) {
c .human = b
}
func (c *Credentials ) AuthTime () time .Time {
return c .authTime
}
func (c *Credentials ) SetAuthTime (t time .Time ) {
c .authTime = t
}
func (c *Credentials ) AuthzAttributes () []string {
s := make ([]string , len (c .groupMembership ))
i := 0
for a := range c .groupMembership {
s [i ] = a
i ++
}
return s
}
func (c *Credentials ) Authenticated () bool {
return c .authenticated
}
func (c *Credentials ) SetAuthenticated (b bool ) {
c .authenticated = b
}
func (c *Credentials ) AddAuthzAttribute (a string ) {
c .groupMembership [a ] = true
}
func (c *Credentials ) RemoveAuthzAttribute (a string ) {
if _ , ok := c .groupMembership [a ]; !ok {
return
}
delete (c .groupMembership , a )
}
func (c *Credentials ) EnableAuthzAttribute (a string ) {
if enabled , ok := c .groupMembership [a ]; ok && !enabled {
c .groupMembership [a ] = true
}
}
func (c *Credentials ) DisableAuthzAttribute (a string ) {
if enabled , ok := c .groupMembership [a ]; ok && enabled {
c .groupMembership [a ] = false
}
}
func (c *Credentials ) Authorized (a string ) bool {
if enabled , ok := c .groupMembership [a ]; ok && enabled {
return true
}
return false
}
func (c *Credentials ) SessionID () string {
return c .sessionID
}
func (c *Credentials ) Expired () bool {
if !c .validUntil .IsZero () && time .Now ().UTC ().After (c .validUntil ) {
return true
}
return false
}
func (c *Credentials ) ValidUntil () time .Time {
return c .validUntil
}
func (c *Credentials ) Attributes () map [string ]interface {} {
return c .attributes
}
func (c *Credentials ) SetAttribute (k string , v interface {}) {
c .attributes [k ] = v
}
func (c *Credentials ) SetAttributes (a map [string ]interface {}) {
c .attributes = a
}
func (c *Credentials ) RemoveAttribute (k string ) {
delete (c .attributes , k )
}
func (c *Credentials ) Marshal () ([]byte , error ) {
gob .Register (map [string ]interface {}{})
gob .Register (ADCredentials {})
buf := new (bytes .Buffer )
enc := gob .NewEncoder (buf )
mc := marshalCredentials {
Username : c .username ,
DisplayName : c .displayName ,
Realm : c .realm ,
CName : c .cname ,
Keytab : c .HasKeytab (),
Password : c .HasPassword (),
Attributes : c .attributes ,
ValidUntil : c .validUntil ,
Authenticated : c .authenticated ,
Human : c .human ,
AuthTime : c .authTime ,
GroupMembership : c .groupMembership ,
SessionID : c .sessionID ,
}
err := enc .Encode (&mc )
if err != nil {
return []byte {}, err
}
return buf .Bytes (), nil
}
func (c *Credentials ) Unmarshal (b []byte ) error {
gob .Register (map [string ]interface {}{})
gob .Register (ADCredentials {})
mc := new (marshalCredentials )
buf := bytes .NewBuffer (b )
dec := gob .NewDecoder (buf )
err := dec .Decode (mc )
if err != nil {
return err
}
c .username = mc .Username
c .displayName = mc .DisplayName
c .realm = mc .Realm
c .cname = mc .CName
c .attributes = mc .Attributes
c .validUntil = mc .ValidUntil
c .authenticated = mc .Authenticated
c .human = mc .Human
c .authTime = mc .AuthTime
c .groupMembership = mc .GroupMembership
c .sessionID = mc .SessionID
return nil
}
func (c *Credentials ) JSON () (string , error ) {
mc := marshalCredentials {
Username : c .username ,
DisplayName : c .displayName ,
Realm : c .realm ,
CName : c .cname ,
Keytab : c .HasKeytab (),
Password : c .HasPassword (),
ValidUntil : c .validUntil ,
Authenticated : c .authenticated ,
Human : c .human ,
AuthTime : c .authTime ,
SessionID : c .sessionID ,
}
b , err := json .MarshalIndent (mc , "" , " " )
if err != nil {
return "" , err
}
return string (b ), nil
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .