Files
2026-07-13 12:32:25 +08:00

146 lines
4.6 KiB
Go

// Copyright 2024 Dolthub, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package auth
import (
"time"
"github.com/dolthub/doltgresql/utils"
)
// Role represents a role/user.
type Role struct {
Name string // rolname
IsSuperUser bool // rolsuper
InheritPrivileges bool // rolinherit
CanCreateRoles bool // rolcreaterole
CanCreateDB bool // rolcreatedb
CanLogin bool // rolcanlogin
IsReplicationRole bool // rolreplication
CanBypassRowLevelSecurity bool // rolbypassrls
ConnectionLimit int32 // rolconnlimit
Password *ScramSha256Password // rolpassword
ValidUntil *time.Time // rolvaliduntil
id RoleID
}
// RoleID represents a Role's ID. IDs are assigned during load and will be stable throughout the server's current
// process. IDs are useful for referencing a specific role without using their name, since names can change. This is
// basically a special OID specific to roles. Eventually, we'll have a proper OID system, but this is a placeholder for
// now.
// TODO: need to replace with id.InternalUser
type RoleID uint64
// CreateDefaultRole creates the given role object with all default values set.
func CreateDefaultRole(name string) Role {
r := createDefaultRoleWithoutID(name)
r.id = RoleID(userIDCounter.Add(1))
return r
}
// createDefaultRoleWithoutID creates a default role, but does not assign an ID.
func createDefaultRoleWithoutID(name string) Role {
return Role{
Name: name,
IsSuperUser: false,
InheritPrivileges: true,
CanCreateRoles: false,
CanCreateDB: false,
CanLogin: false,
IsReplicationRole: false,
CanBypassRowLevelSecurity: false,
ConnectionLimit: -1,
Password: nil,
ValidUntil: nil,
id: RoleID(0),
}
}
// ID returns this Role's ID value.
func (r *Role) ID() RoleID {
return r.id
}
// IsValid returns true when the role has a valid ID.
func (r *Role) IsValid() bool {
return r.id.IsValid()
}
// IsValid returns true when the RoleID has a valid value. It does not indicate that the RoleID is attached to a role
// that actually exists.
func (id RoleID) IsValid() bool {
return id != RoleID(0)
}
// serialize writes the Role to the given writer.
func (r *Role) serialize(writer *utils.Writer) {
// Version 0
writer.String(r.Name)
writer.Bool(r.IsSuperUser)
writer.Bool(r.InheritPrivileges)
writer.Bool(r.CanCreateRoles)
writer.Bool(r.CanCreateDB)
writer.Bool(r.CanLogin)
writer.Bool(r.IsReplicationRole)
writer.Bool(r.CanBypassRowLevelSecurity)
writer.Int32(r.ConnectionLimit)
if r.Password != nil {
writer.Bool(true)
writer.Uint32(r.Password.Iterations)
writer.ByteSlice(r.Password.Salt)
writer.ByteSlice(r.Password.StoredKey)
writer.ByteSlice(r.Password.ServerKey)
} else {
writer.Bool(false)
}
if r.ValidUntil != nil {
writer.Bool(true)
writer.Int64(r.ValidUntil.UnixMicro())
} else {
writer.Bool(false)
}
writer.Uint64(uint64(r.id))
}
// deserialize reads the Role from the given reader.
func (r *Role) deserialize(version uint32, reader *utils.Reader) {
switch version {
case 0, 1:
r.Name = reader.String()
r.IsSuperUser = reader.Bool()
r.InheritPrivileges = reader.Bool()
r.CanCreateRoles = reader.Bool()
r.CanCreateDB = reader.Bool()
r.CanLogin = reader.Bool()
r.IsReplicationRole = reader.Bool()
r.CanBypassRowLevelSecurity = reader.Bool()
r.ConnectionLimit = reader.Int32()
if reader.Bool() {
r.Password = &ScramSha256Password{}
r.Password.Iterations = reader.Uint32()
r.Password.Salt = reader.ByteSlice()
r.Password.StoredKey = reader.ByteSlice()
r.Password.ServerKey = reader.ByteSlice()
}
if reader.Bool() {
t := time.UnixMicro(reader.Int64())
r.ValidUntil = &t
}
r.id = RoleID(reader.Uint64())
default:
panic("unexpected version in Role")
}
}