mirror of
https://github.com/fhmq/hmq.git
synced 2026-09-01 15:24:53 +00:00
Plugins support (#46)
* modify * update * add acl * add feature * update dockerfile * add deploy * update * update * plugins * plugins * update * update * update * fixed * remove * fixed * add log * update * fixed * update * fix config * add http api * add http api * resp * add config for work chan * update * fixed * update * disable trace * fixed * change acl * fixed * fixed res * dd * dd * ddd * dd * update * fixed * update * add * fixed * update key * add log * update * format * update * update auth * update * update readme * added * update * fixed * fixed * fix * upade * update * update
This commit is contained in:
+348
@@ -0,0 +1,348 @@
|
||||
package credentials
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/jcmturner/gofork/encoding/asn1"
|
||||
"gopkg.in/jcmturner/gokrb5.v7/types"
|
||||
)
|
||||
|
||||
const (
|
||||
headerFieldTagKDCOffset = 1
|
||||
)
|
||||
|
||||
// The first byte of the file always has the value 5.
|
||||
// The value of the second byte contains the version number (1 through 4)
|
||||
// Versions 1 and 2 of the file format use native byte order for integer representations.
|
||||
// Versions 3 and 4 always use big-endian byte order
|
||||
// After the two-byte version indicator, the file has three parts:
|
||||
// 1) the header (in version 4 only)
|
||||
// 2) the default principal name
|
||||
// 3) a sequence of credentials
|
||||
|
||||
// CCache is the file credentials cache as define here: https://web.mit.edu/kerberos/krb5-latest/doc/formats/ccache_file_format.html
|
||||
type CCache struct {
|
||||
Version uint8
|
||||
Header header
|
||||
DefaultPrincipal principal
|
||||
Credentials []*Credential
|
||||
Path string
|
||||
}
|
||||
|
||||
type header struct {
|
||||
length uint16
|
||||
fields []headerField
|
||||
}
|
||||
|
||||
type headerField struct {
|
||||
tag uint16
|
||||
length uint16
|
||||
value []byte
|
||||
}
|
||||
|
||||
// Credential cache entry principal struct.
|
||||
type principal struct {
|
||||
Realm string
|
||||
PrincipalName types.PrincipalName
|
||||
}
|
||||
|
||||
// Credential holds a Kerberos client's ccache credential information.
|
||||
type Credential struct {
|
||||
Client principal
|
||||
Server principal
|
||||
Key types.EncryptionKey
|
||||
AuthTime time.Time
|
||||
StartTime time.Time
|
||||
EndTime time.Time
|
||||
RenewTill time.Time
|
||||
IsSKey bool
|
||||
TicketFlags asn1.BitString
|
||||
Addresses []types.HostAddress
|
||||
AuthData []types.AuthorizationDataEntry
|
||||
Ticket []byte
|
||||
SecondTicket []byte
|
||||
}
|
||||
|
||||
// LoadCCache loads a credential cache file into a CCache type.
|
||||
func LoadCCache(cpath string) (*CCache, error) {
|
||||
c := new(CCache)
|
||||
b, err := ioutil.ReadFile(cpath)
|
||||
if err != nil {
|
||||
return c, err
|
||||
}
|
||||
err = c.Unmarshal(b)
|
||||
return c, err
|
||||
}
|
||||
|
||||
// Unmarshal a byte slice of credential cache data into CCache type.
|
||||
func (c *CCache) Unmarshal(b []byte) error {
|
||||
p := 0
|
||||
//The first byte of the file always has the value 5
|
||||
if int8(b[p]) != 5 {
|
||||
return errors.New("Invalid credential cache data. First byte does not equal 5")
|
||||
}
|
||||
p++
|
||||
//Get credential cache version
|
||||
//The second byte contains the version number (1 to 4)
|
||||
c.Version = b[p]
|
||||
if c.Version < 1 || c.Version > 4 {
|
||||
return errors.New("Invalid credential cache data. Keytab version is not within 1 to 4")
|
||||
}
|
||||
p++
|
||||
//Version 1 or 2 of the file format uses native byte order for integer representations. Versions 3 & 4 always uses big-endian byte order
|
||||
var endian binary.ByteOrder
|
||||
endian = binary.BigEndian
|
||||
if (c.Version == 1 || c.Version == 2) && isNativeEndianLittle() {
|
||||
endian = binary.LittleEndian
|
||||
}
|
||||
if c.Version == 4 {
|
||||
err := parseHeader(b, &p, c, &endian)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
c.DefaultPrincipal = parsePrincipal(b, &p, c, &endian)
|
||||
for p < len(b) {
|
||||
cred, err := parseCredential(b, &p, c, &endian)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.Credentials = append(c.Credentials, cred)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func parseHeader(b []byte, p *int, c *CCache, e *binary.ByteOrder) error {
|
||||
if c.Version != 4 {
|
||||
return errors.New("Credentials cache version is not 4 so there is no header to parse.")
|
||||
}
|
||||
h := header{}
|
||||
h.length = uint16(readInt16(b, p, e))
|
||||
for *p <= int(h.length) {
|
||||
f := headerField{}
|
||||
f.tag = uint16(readInt16(b, p, e))
|
||||
f.length = uint16(readInt16(b, p, e))
|
||||
f.value = b[*p : *p+int(f.length)]
|
||||
*p += int(f.length)
|
||||
if !f.valid() {
|
||||
return errors.New("Invalid credential cache header found")
|
||||
}
|
||||
h.fields = append(h.fields, f)
|
||||
}
|
||||
c.Header = h
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parse the Keytab bytes of a principal into a Keytab entry's principal.
|
||||
func parsePrincipal(b []byte, p *int, c *CCache, e *binary.ByteOrder) (princ principal) {
|
||||
if c.Version != 1 {
|
||||
//Name Type is omitted in version 1
|
||||
princ.PrincipalName.NameType = readInt32(b, p, e)
|
||||
}
|
||||
nc := int(readInt32(b, p, e))
|
||||
if c.Version == 1 {
|
||||
//In version 1 the number of components includes the realm. Minus 1 to make consistent with version 2
|
||||
nc--
|
||||
}
|
||||
lenRealm := readInt32(b, p, e)
|
||||
princ.Realm = string(readBytes(b, p, int(lenRealm), e))
|
||||
for i := 0; i < nc; i++ {
|
||||
l := readInt32(b, p, e)
|
||||
princ.PrincipalName.NameString = append(princ.PrincipalName.NameString, string(readBytes(b, p, int(l), e)))
|
||||
}
|
||||
return princ
|
||||
}
|
||||
|
||||
func parseCredential(b []byte, p *int, c *CCache, e *binary.ByteOrder) (cred *Credential, err error) {
|
||||
cred = new(Credential)
|
||||
cred.Client = parsePrincipal(b, p, c, e)
|
||||
cred.Server = parsePrincipal(b, p, c, e)
|
||||
key := types.EncryptionKey{}
|
||||
key.KeyType = int32(readInt16(b, p, e))
|
||||
if c.Version == 3 {
|
||||
//repeated twice in version 3
|
||||
key.KeyType = int32(readInt16(b, p, e))
|
||||
}
|
||||
key.KeyValue = readData(b, p, e)
|
||||
cred.Key = key
|
||||
cred.AuthTime = readTimestamp(b, p, e)
|
||||
cred.StartTime = readTimestamp(b, p, e)
|
||||
cred.EndTime = readTimestamp(b, p, e)
|
||||
cred.RenewTill = readTimestamp(b, p, e)
|
||||
if ik := readInt8(b, p, e); ik == 0 {
|
||||
cred.IsSKey = false
|
||||
} else {
|
||||
cred.IsSKey = true
|
||||
}
|
||||
cred.TicketFlags = types.NewKrbFlags()
|
||||
cred.TicketFlags.Bytes = readBytes(b, p, 4, e)
|
||||
l := int(readInt32(b, p, e))
|
||||
cred.Addresses = make([]types.HostAddress, l, l)
|
||||
for i := range cred.Addresses {
|
||||
cred.Addresses[i] = readAddress(b, p, e)
|
||||
}
|
||||
l = int(readInt32(b, p, e))
|
||||
cred.AuthData = make([]types.AuthorizationDataEntry, l, l)
|
||||
for i := range cred.AuthData {
|
||||
cred.AuthData[i] = readAuthDataEntry(b, p, e)
|
||||
}
|
||||
cred.Ticket = readData(b, p, e)
|
||||
cred.SecondTicket = readData(b, p, e)
|
||||
return
|
||||
}
|
||||
|
||||
// GetClientPrincipalName returns a PrincipalName type for the client the credentials cache is for.
|
||||
func (c *CCache) GetClientPrincipalName() types.PrincipalName {
|
||||
return c.DefaultPrincipal.PrincipalName
|
||||
}
|
||||
|
||||
// GetClientRealm returns the reals of the client the credentials cache is for.
|
||||
func (c *CCache) GetClientRealm() string {
|
||||
return c.DefaultPrincipal.Realm
|
||||
}
|
||||
|
||||
// GetClientCredentials returns a Credentials object representing the client of the credentials cache.
|
||||
func (c *CCache) GetClientCredentials() *Credentials {
|
||||
return &Credentials{
|
||||
username: c.DefaultPrincipal.PrincipalName.PrincipalNameString(),
|
||||
realm: c.GetClientRealm(),
|
||||
cname: c.DefaultPrincipal.PrincipalName,
|
||||
}
|
||||
}
|
||||
|
||||
// Contains tests if the cache contains a credential for the provided server PrincipalName
|
||||
func (c *CCache) Contains(p types.PrincipalName) bool {
|
||||
for _, cred := range c.Credentials {
|
||||
if cred.Server.PrincipalName.Equal(p) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetEntry returns a specific credential for the PrincipalName provided.
|
||||
func (c *CCache) GetEntry(p types.PrincipalName) (*Credential, bool) {
|
||||
cred := new(Credential)
|
||||
var found bool
|
||||
for i := range c.Credentials {
|
||||
if c.Credentials[i].Server.PrincipalName.Equal(p) {
|
||||
cred = c.Credentials[i]
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return cred, false
|
||||
}
|
||||
return cred, true
|
||||
}
|
||||
|
||||
// GetEntries filters out configuration entries an returns a slice of credentials.
|
||||
func (c *CCache) GetEntries() []*Credential {
|
||||
creds := make([]*Credential, 0)
|
||||
for _, cred := range c.Credentials {
|
||||
// Filter out configuration entries
|
||||
if strings.HasPrefix(cred.Server.Realm, "X-CACHECONF") {
|
||||
continue
|
||||
}
|
||||
creds = append(creds, cred)
|
||||
}
|
||||
return creds
|
||||
}
|
||||
|
||||
func (h *headerField) valid() bool {
|
||||
// At this time there is only one defined header field.
|
||||
// Its tag value is 1, its length is always 8.
|
||||
// Its contents are two 32-bit integers giving the seconds and microseconds
|
||||
// of the time offset of the KDC relative to the client.
|
||||
// Adding this offset to the current time on the client should give the current time on the KDC, if that offset has not changed since the initial authentication.
|
||||
|
||||
// Done as a switch in case other tag values are added in the future.
|
||||
switch h.tag {
|
||||
case headerFieldTagKDCOffset:
|
||||
if h.length != 8 || len(h.value) != 8 {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func readData(b []byte, p *int, e *binary.ByteOrder) []byte {
|
||||
l := readInt32(b, p, e)
|
||||
return readBytes(b, p, int(l), e)
|
||||
}
|
||||
|
||||
func readAddress(b []byte, p *int, e *binary.ByteOrder) types.HostAddress {
|
||||
a := types.HostAddress{}
|
||||
a.AddrType = int32(readInt16(b, p, e))
|
||||
a.Address = readData(b, p, e)
|
||||
return a
|
||||
}
|
||||
|
||||
func readAuthDataEntry(b []byte, p *int, e *binary.ByteOrder) types.AuthorizationDataEntry {
|
||||
a := types.AuthorizationDataEntry{}
|
||||
a.ADType = int32(readInt16(b, p, e))
|
||||
a.ADData = readData(b, p, e)
|
||||
return a
|
||||
}
|
||||
|
||||
// Read bytes representing a timestamp.
|
||||
func readTimestamp(b []byte, p *int, e *binary.ByteOrder) time.Time {
|
||||
return time.Unix(int64(readInt32(b, p, e)), 0)
|
||||
}
|
||||
|
||||
// Read bytes representing an eight bit integer.
|
||||
func readInt8(b []byte, p *int, e *binary.ByteOrder) (i int8) {
|
||||
buf := bytes.NewBuffer(b[*p : *p+1])
|
||||
binary.Read(buf, *e, &i)
|
||||
*p++
|
||||
return
|
||||
}
|
||||
|
||||
// Read bytes representing a sixteen bit integer.
|
||||
func readInt16(b []byte, p *int, e *binary.ByteOrder) (i int16) {
|
||||
buf := bytes.NewBuffer(b[*p : *p+2])
|
||||
binary.Read(buf, *e, &i)
|
||||
*p += 2
|
||||
return
|
||||
}
|
||||
|
||||
// Read bytes representing a thirty two bit integer.
|
||||
func readInt32(b []byte, p *int, e *binary.ByteOrder) (i int32) {
|
||||
buf := bytes.NewBuffer(b[*p : *p+4])
|
||||
binary.Read(buf, *e, &i)
|
||||
*p += 4
|
||||
return
|
||||
}
|
||||
|
||||
func readBytes(b []byte, p *int, s int, e *binary.ByteOrder) []byte {
|
||||
buf := bytes.NewBuffer(b[*p : *p+s])
|
||||
r := make([]byte, s)
|
||||
binary.Read(buf, *e, &r)
|
||||
*p += s
|
||||
return r
|
||||
}
|
||||
|
||||
func isNativeEndianLittle() bool {
|
||||
var x = 0x012345678
|
||||
var p = unsafe.Pointer(&x)
|
||||
var bp = (*[4]byte)(p)
|
||||
|
||||
var endian bool
|
||||
if 0x01 == bp[0] {
|
||||
endian = false
|
||||
} else if (0x78 & 0xff) == (bp[0] & 0xff) {
|
||||
endian = true
|
||||
} else {
|
||||
// Default to big endian
|
||||
endian = false
|
||||
}
|
||||
return endian
|
||||
}
|
||||
+309
@@ -0,0 +1,309 @@
|
||||
// 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
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
Reference in New Issue
Block a user