146 lines
4.6 KiB
Go
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")
|
|
}
|
|
}
|