1
Fork 0
mirror of https://github.com/jech/galene.git synced 2024-11-22 08:35:57 +01:00

Replace ClientPermissions with a list of strings.

Now that we support external auth, the permissions list is
open-ended.  Make it a list for simplicity.
This commit is contained in:
Juliusz Chroboczek 2022-02-19 23:43:44 +01:00
parent 439dbabaa5
commit a86fb08f6c
11 changed files with 213 additions and 175 deletions

View file

@ -385,7 +385,7 @@ allowed to join, then the authorisation server replies with a signed JWT
{
"sub": username,
"aud": "https://galene.example.org/group/groupname",
"permissions": ["present": true],
"permissions": ["present"],
"iat": now,
"exp": now + 30s,
"iss": authorisation server URL

View file

@ -59,21 +59,19 @@ func (client *Client) Username() string {
return "RECORDING"
}
func (client *Client) SetPermissions(perms group.ClientPermissions) {
func (client *Client) SetPermissions(perms []string) {
return
}
func (client *Client) Permissions() group.ClientPermissions {
return group.ClientPermissions{
System: true,
}
func (client *Client) Permissions() []string {
return []string{"system"}
}
func (client *Client) Data() map[string]interface{} {
return nil
}
func (client *Client) PushClient(group, kind, id, username string, permissions group.ClientPermissions, data map[string]interface{}) error {
func (client *Client) PushClient(group, kind, id, username string, perms []string, data map[string]interface{}) error {
return nil
}

View file

@ -81,13 +81,6 @@ type ClientPattern struct {
Password *Password `json:"password,omitempty"`
}
type ClientPermissions struct {
Op bool `json:"op,omitempty"`
Present bool `json:"present,omitempty"`
Record bool `json:"record,omitempty"`
System bool `json:"system,omitempty"`
}
type ClientCredentials struct {
System bool
Username string
@ -99,12 +92,12 @@ type Client interface {
Group() *Group
Id() string
Username() string
Permissions() ClientPermissions
SetPermissions(ClientPermissions)
Permissions() []string
SetPermissions([]string)
Data() map[string]interface{}
PushConn(g *Group, id string, conn conn.Up, tracks []conn.UpTrack, replace string) error
RequestConns(target Client, g *Group, id string) error
Joined(group, kind string) error
PushClient(group, kind, id, username string, permissions ClientPermissions, data map[string]interface{}) error
PushClient(group, kind, id, username string, perms []string, data map[string]interface{}) error
Kick(id, user, message string) error
}

View file

@ -544,6 +544,15 @@ func deleteUnlocked(g *Group) bool {
return true
}
func member(v string, l []string) bool {
for _, w := range l {
if v == w {
return true
}
}
return false
}
func AddClient(group string, c Client, creds ClientCredentials) (*Group, error) {
g, err := Add(group, nil)
if err != nil {
@ -555,7 +564,7 @@ func AddClient(group string, c Client, creds ClientCredentials) (*Group, error)
clients := g.getClientsUnlocked(nil)
if !c.Permissions().System {
if !member("system", c.Permissions()) {
perms, err := g.description.GetPermission(group, creds)
if err != nil {
return nil, err
@ -563,7 +572,7 @@ func AddClient(group string, c Client, creds ClientCredentials) (*Group, error)
c.SetPermissions(perms)
if !perms.Op {
if !member("op", perms) {
if g.locked != nil {
m := *g.locked
if m == "" {
@ -574,7 +583,7 @@ func AddClient(group string, c Client, creds ClientCredentials) (*Group, error)
if g.description.Autokick {
ops := false
for _, c := range clients {
if c.Permissions().Op {
if member("op", c.Permissions()) {
ops = true
break
}
@ -588,7 +597,7 @@ func AddClient(group string, c Client, creds ClientCredentials) (*Group, error)
}
}
if !perms.Op && g.description.MaxClients > 0 {
if !member("op", perms) && g.description.MaxClients > 0 {
if len(g.clients) >= g.description.MaxClients {
return nil, UserError("too many users")
}
@ -627,7 +636,7 @@ func autoLockKick(g *Group, clients []Client) {
return
}
for _, c := range clients {
if c.Permissions().Op {
if member("op", c.Permissions()) {
return
}
}
@ -665,7 +674,7 @@ func DelClient(c Client) {
c.Joined(g.Name(), "leave")
for _, cc := range clients {
cc.PushClient(
g.Name(), "delete", c.Id(), "", ClientPermissions{}, nil,
g.Name(), "delete", c.Id(), "", nil, nil,
)
}
autoLockKick(g, clients)
@ -1066,49 +1075,49 @@ func GetDescription(name string) (*Description, error) {
return &desc, nil
}
func (desc *Description) GetPermission(group string, creds ClientCredentials) (ClientPermissions, error) {
var p ClientPermissions
func (desc *Description) GetPermission(group string, creds ClientCredentials) ([]string, error) {
if !desc.AllowAnonymous && creds.Username == "" {
return p, ErrAnonymousNotAuthorised
return nil, ErrAnonymousNotAuthorised
}
if creds.Token == "" {
if found, good := matchClient(group, creds, desc.Op); found {
if good {
p.Op = true
p.Present = true
var p []string
p = []string{"op", "present"}
if desc.AllowRecording {
p.Record = true
p = append(p, "record")
}
return p, nil
}
return p, ErrNotAuthorised
return nil, ErrNotAuthorised
}
if found, good := matchClient(group, creds, desc.Presenter); found {
if good {
p.Present = true
return p, nil
return []string{"present"}, nil
}
return p, ErrNotAuthorised
return nil, ErrNotAuthorised
}
if found, good := matchClient(group, creds, desc.Other); found {
if good {
return p, nil
return nil, nil
}
return p, ErrNotAuthorised
return nil, ErrNotAuthorised
}
return nil, ErrNotAuthorised
}
if creds.Token != "" {
aud, perms, err := token.Valid(
creds.Username, creds.Token, desc.AuthKeys,
)
if err != nil {
log.Printf("Token authentication: %v", err)
return p, ErrNotAuthorised
return nil, ErrNotAuthorised
}
conf, err := GetConfiguration()
if err != nil {
log.Printf("Read config.json: %v", err)
return p, err
return nil, err
}
ok := false
for _, u := range aud {
@ -1133,15 +1142,9 @@ func (desc *Description) GetPermission(group string, creds ClientCredentials) (C
}
}
if !ok {
return p, ErrNotAuthorised
return nil, ErrNotAuthorised
}
p.Op, _ = perms["op"].(bool)
p.Present, _ = perms["present"].(bool)
p.Record, _ = perms["record"].(bool)
return p, nil
}
return p, ErrNotAuthorised
return perms, nil
}
type Status struct {

View file

@ -132,29 +132,29 @@ var badClients = []ClientCredentials{
type credPerm struct {
c ClientCredentials
p ClientPermissions
p []string
}
var goodClients = []credPerm{
{
ClientCredentials{Username: "jch", Password: "topsecret"},
ClientPermissions{Op: true, Present: true},
[]string{"op", "present"},
},
{
ClientCredentials{Username: "john", Password: "secret"},
ClientPermissions{Present: true},
[]string{"present"},
},
{
ClientCredentials{Username: "john", Password: "secret2"},
ClientPermissions{Present: true},
[]string{"present"},
},
{
ClientCredentials{Username: "james", Password: "secret3"},
ClientPermissions{},
nil,
},
{
ClientCredentials{Username: "paul", Password: "secret3"},
ClientPermissions{},
nil,
},
}

View file

@ -56,7 +56,7 @@ type webClient struct {
group *group.Group
id string
username string
permissions group.ClientPermissions
permissions []string
data map[string]interface{}
requested map[string][]string
done chan struct{}
@ -86,7 +86,7 @@ func (c *webClient) Username() string {
return c.username
}
func (c *webClient) Permissions() group.ClientPermissions {
func (c *webClient) Permissions() []string {
return c.permissions
}
@ -94,13 +94,13 @@ func (c *webClient) Data() map[string]interface{} {
return c.data
}
func (c *webClient) SetPermissions(perms group.ClientPermissions) {
func (c *webClient) SetPermissions(perms []string) {
c.permissions = perms
}
func (c *webClient) PushClient(group, kind, id, username string, permissions group.ClientPermissions, data map[string]interface{}) error {
func (c *webClient) PushClient(group, kind, id, username string, perms []string, data map[string]interface{}) error {
return c.action(pushClientAction{
group, kind, id, username, permissions, data,
group, kind, id, username, perms, data,
})
}
@ -115,7 +115,7 @@ type clientMessage struct {
Password string `json:"password,omitempty"`
Token string `json:"token,omitempty"`
Privileged bool `json:"privileged,omitempty"`
Permissions *group.ClientPermissions `json:"permissions,omitempty"`
Permissions []string `json:"permissions,omitempty"`
Status *group.Status `json:"status,omitempty"`
Data map[string]interface{} `json:"data,omitempty"`
Group string `json:"group,omitempty"`
@ -900,7 +900,7 @@ type pushClientAction struct {
kind string
id string
username string
permissions group.ClientPermissions
permissions []string
data map[string]interface{}
}
@ -919,6 +919,33 @@ type kickAction struct {
var errEmptyId = group.ProtocolError("empty id")
func member(v string, l []string) bool {
for _, w := range l {
if v == w {
return true
}
}
return false
}
func remove(v string, l []string) []string {
for i, w := range l {
if v == w {
l = append(l[:i], l[i+1:]...)
return l
}
}
return l
}
func addnew(v string, l []string) []string {
if member(v, l) {
return l
}
l = append(l, v)
return l
}
func clientLoop(c *webClient, ws *websocket.Conn) error {
read := make(chan interface{}, 1)
go clientReader(ws, read, c.done)
@ -1102,12 +1129,13 @@ func handleAction(c *webClient, a interface{}) error {
log.Printf("got client for wrong group")
return nil
}
perms := append([]string(nil), a.permissions...)
return c.write(clientMessage{
Type: "user",
Kind: a.kind,
Id: a.id,
Username: a.username,
Permissions: &a.permissions,
Permissions: perms,
Data: a.data,
})
case joinedAction:
@ -1121,13 +1149,13 @@ func handleAction(c *webClient, a interface{}) error {
data = g.Data()
}
}
perms := c.permissions
perms := append([]string(nil), c.permissions...)
return c.write(clientMessage{
Type: "joined",
Kind: a.kind,
Group: a.group,
Username: c.username,
Permissions: &perms,
Permissions: perms,
Status: status,
Data: data,
RTCConfiguration: ice.ICEConfiguration(),
@ -1137,18 +1165,18 @@ func handleAction(c *webClient, a interface{}) error {
if g == nil {
return errors.New("Permissions changed in no group")
}
perms := c.permissions
perms := append([]string(nil), c.permissions...)
status := g.Status(true)
c.write(clientMessage{
Type: "joined",
Kind: "change",
Group: g.Name(),
Username: c.username,
Permissions: &perms,
Permissions: perms,
Status: &status,
RTCConfiguration: ice.ICEConfiguration(),
})
if !c.permissions.Present {
if member("present", c.permissions) {
up := getUpConns(c)
for _, u := range up {
err := delUpConn(
@ -1220,7 +1248,7 @@ func leaveGroup(c *webClient) {
}
group.DelClient(c)
c.permissions = group.ClientPermissions{}
c.permissions = nil
c.data = nil
c.requested = make(map[string][]string)
c.group = nil
@ -1260,17 +1288,17 @@ func setPermissions(g *group.Group, id string, perm string) error {
switch perm {
case "op":
c.permissions.Op = true
c.permissions = addnew("op", c.permissions)
if g.Description().AllowRecording {
c.permissions.Record = true
c.permissions = addnew("record", c.permissions)
}
case "unop":
c.permissions.Op = false
c.permissions.Record = false
c.permissions = remove("op", c.permissions)
c.permissions = remove("record", c.permissions)
case "present":
c.permissions.Present = true
c.permissions = addnew("present", c.permissions)
case "unpresent":
c.permissions.Present = false
c.permissions = remove("present", c.permissions)
default:
return group.UserError("unknown permission")
}
@ -1356,7 +1384,6 @@ func handleClientMessage(c *webClient, m clientMessage) error {
Kind: "fail",
Group: m.Group,
Username: c.username,
Permissions: &group.ClientPermissions{},
Value: s,
})
}
@ -1368,7 +1395,6 @@ func handleClientMessage(c *webClient, m clientMessage) error {
Kind: "redirect",
Group: m.Group,
Username: c.username,
Permissions: &group.ClientPermissions{},
Value: redirect,
})
}
@ -1407,7 +1433,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
if m.Id == "" {
return errEmptyId
}
if !c.permissions.Present {
if !member("present", c.permissions) {
if m.Replace != "" {
delUpConn(c, m.Replace, c.id, true)
}
@ -1508,7 +1534,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
Source: m.Source,
Dest: m.Dest,
Username: m.Username,
Privileged: c.permissions.Op,
Privileged: member("op", c.permissions),
Time: tm,
Kind: m.Kind,
NoEcho: m.NoEcho,
@ -1554,7 +1580,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
log.Printf("broadcast(clearchat): %v", err)
}
case "lock", "unlock":
if !c.permissions.Op {
if !member("op", c.permissions) {
return c.error(group.UserError("not authorised"))
}
message := ""
@ -1564,7 +1590,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
}
g.SetLocked(m.Kind == "lock", message)
case "record":
if !c.permissions.Record {
if !member("record", c.permissions) {
return c.error(group.UserError("not authorised"))
}
for _, cc := range g.GetClients(c) {
@ -1585,7 +1611,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
}
requestConns(disk, c.group, "")
case "unrecord":
if !c.permissions.Record {
if !member("record", c.permissions) {
return c.error(group.UserError("not authorised"))
}
for _, cc := range g.GetClients(c) {
@ -1596,7 +1622,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
}
}
case "subgroups":
if !c.permissions.Op {
if !member("op", c.permissions) {
return c.error(group.UserError("not authorised"))
}
s := ""
@ -1616,7 +1642,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
Value: s,
})
case "setdata":
if !c.permissions.Op {
if !member("op", c.permissions) {
return c.error(group.UserError("not authorised"))
}
data, ok := m.Value.(map[string]interface{})
@ -1636,7 +1662,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
}
switch m.Kind {
case "op", "unop", "present", "unpresent":
if !c.permissions.Op {
if !member("op", c.permissions) {
return c.error(group.UserError("not authorised"))
}
err := setPermissions(g, m.Dest, m.Kind)
@ -1644,7 +1670,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
return c.error(err)
}
case "kick":
if !c.permissions.Op {
if !member("op", c.permissions) {
return c.error(group.UserError("not authorised"))
}
message := ""
@ -1769,7 +1795,7 @@ func clientWriter(conn *websocket.Conn, ch <-chan interface{}, done chan<- struc
}
func (c *webClient) Warn(oponly bool, message string) error {
if oponly && !c.permissions.Op {
if oponly && !member("op", c.permissions) {
return nil
}

View file

@ -402,6 +402,7 @@ function setVisibility(id, visible) {
function setButtonsVisibility() {
let connected = serverConnection && serverConnection.socket;
let permissions = serverConnection.permissions;
let present = permissions.indexOf('present') >= 0;
let local = !!findUpMedia('camera');
let canWebrtc = !(typeof RTCPeerConnection === 'undefined');
let canFile =
@ -413,19 +414,19 @@ function setButtonsVisibility() {
let mobilelayout = isMobileLayout();
// don't allow multiple presentations
setVisibility('presentbutton', canWebrtc && permissions.present && !local);
setVisibility('presentbutton', canWebrtc && present && !local);
setVisibility('unpresentbutton', local);
setVisibility('mutebutton', !connected || permissions.present);
setVisibility('mutebutton', !connected || present);
// allow multiple shared documents
setVisibility('sharebutton', canWebrtc && permissions.present &&
setVisibility('sharebutton', canWebrtc && present &&
('getDisplayMedia' in navigator.mediaDevices));
setVisibility('mediaoptions', permissions.present);
setVisibility('sendform', permissions.present);
setVisibility('simulcastform', permissions.present);
setVisibility('fileform', canFile && permissions.present);
setVisibility('mediaoptions', present);
setVisibility('sendform', present);
setVisibility('simulcastform', present);
setVisibility('fileform', canFile && present);
setVisibility('collapse-video', mediacount && mobilelayout);
}
@ -2012,9 +2013,9 @@ function userMenu(elt) {
items.push({label: 'Send file', onClick: () => {
sendFile(id);
}});
if(serverConnection.permissions.op) {
if(serverConnection.permissions.indexOf('op') >= 0) {
items.push({type: 'seperator'}); // sic
if(user.permissions.present)
if(user.permissions.indexOf('present') >= 0)
items.push({label: 'Forbid presenting', onClick: () => {
serverConnection.userAction('unpresent', id);
}});
@ -2139,12 +2140,14 @@ function gotUser(id, kind) {
function displayUsername() {
document.getElementById('userspan').textContent = username;
let op = serverConnection.permissions.indexOf('op') >= 0;
let present = serverConnection.permissions.indexOf('present') >= 0;
let text = '';
if(serverConnection.permissions.op && serverConnection.permissions.present)
if(op && present)
text = '(op, presenter)';
else if(serverConnection.permissions.op)
else if(op)
text = 'operator';
else if(serverConnection.permissions.present)
else if(present)
text = 'presenter';
document.getElementById('permspan').textContent = text;
}
@ -2178,7 +2181,7 @@ function setTitle(title) {
/**
* @this {ServerConnection}
* @param {string} group
* @param {Object<string,boolean>} perms
* @param {Array<string>} perms
* @param {Object<string,any>} status
* @param {Object<string,any>} data
* @param {string} message
@ -2226,7 +2229,8 @@ async function gotJoined(kind, group, perms, status, data, message) {
else
this.request(mapRequest(getSettings().request));
if(serverConnection.permissions.present && !findUpMedia('camera')) {
if(serverConnection.permissions.indexOf('present') >= 0 &&
!findUpMedia('camera')) {
if(present) {
if(present === 'mike')
updateSettings({video: ''});
@ -3050,14 +3054,14 @@ let commands = {};
function operatorPredicate() {
if(serverConnection && serverConnection.permissions &&
serverConnection.permissions.op)
serverConnection.permissions.indexOf('op') >= 0)
return null;
return 'You are not an operator';
}
function recordingPredicate() {
if(serverConnection && serverConnection.permissions &&
serverConnection.permissions.record)
serverConnection.permissions.indexOf('record') >= 0)
return null;
return 'You are not allowed to record';
}

View file

@ -63,7 +63,7 @@ function newLocalId() {
/**
* @typedef {Object} user
* @property {string} username
* @property {Object<string,boolean>} permissions
* @property {Array<string>} permissions
* @property {Object<string,any>} data
* @property {Object<string,Object<string,boolean>>} down
*/
@ -126,9 +126,9 @@ function ServerConnection() {
/**
* The permissions granted to this connection.
*
* @type {Object<string,boolean>}
* @type {Array<string>}
*/
this.permissions = {};
this.permissions = [];
/**
* userdata is a convenient place to attach data to a ServerConnection.
* It is not used by the library.
@ -164,7 +164,7 @@ function ServerConnection() {
*
* kind is one of 'join', 'fail', 'change' or 'leave'.
*
* @type{(this: ServerConnection, kind: string, group: string, permissions: Object<string,boolean>, status: Object<string,any>, data: Object<string,any>, message: string) => void}
* @type{(this: ServerConnection, kind: string, group: string, permissions: Array<string>, status: Object<string,any>, data: Object<string,any>, message: string) => void}
*/
this.onjoined = null;
/**
@ -207,7 +207,7 @@ function ServerConnection() {
* @property {string} [password]
* @property {string} [token]
* @property {boolean} [privileged]
* @property {Object<string,boolean>} [permissions]
* @property {Array<string>} [permissions]
* @property {Object<string,any>} [status]
* @property {Object<string,any>} [data]
* @property {string} [group]
@ -271,7 +271,7 @@ ServerConnection.prototype.connect = async function(url) {
resolve(sc);
};
this.socket.onclose = function(e) {
sc.permissions = {};
sc.permissions = [];
for(let id in sc.up) {
let c = sc.up[id];
c.close();
@ -286,7 +286,7 @@ ServerConnection.prototype.connect = async function(url) {
sc.onuser.call(sc, id, 'delete');
}
if(sc.group && sc.onjoined)
sc.onjoined.call(sc, 'leave', sc.group, {}, {}, {}, '');
sc.onjoined.call(sc, 'leave', sc.group, [], {}, {}, '');
sc.group = null;
sc.username = null;
if(sc.onclose)
@ -337,7 +337,7 @@ ServerConnection.prototype.connect = async function(url) {
}
if(sc.onjoined)
sc.onjoined.call(sc, m.kind, m.group,
m.permissions || {},
m.permissions || [],
m.status, m.data,
m.value || null);
break;
@ -348,7 +348,7 @@ ServerConnection.prototype.connect = async function(url) {
console.warn(`Duplicate user ${m.id} ${m.username}`);
sc.users[m.id] = {
username: m.username,
permissions: m.permissions || {},
permissions: m.permissions || [],
data: m.data || {},
down: {},
};
@ -358,13 +358,13 @@ ServerConnection.prototype.connect = async function(url) {
console.warn(`Unknown user ${m.id} ${m.username}`);
sc.users[m.id] = {
username: m.username,
permissions: m.permissions || {},
permissions: m.permissions || [],
data: m.data || {},
down: {},
};
} else {
sc.users[m.id].username = m.username;
sc.users[m.id].permissions = m.permissions || {};
sc.users[m.id].permissions = m.permissions || [];
sc.users[m.id].data = m.data || {};
}
break;

View file

@ -105,7 +105,7 @@ func getKey(header map[string]interface{}, keys []map[string]interface{}) (inter
return nil, errors.New("key not found")
}
func Valid(username, token string, keys []map[string]interface{}) ([]string, map[string]interface{}, error) {
func Valid(username, token string, keys []map[string]interface{}) ([]string, []string, error) {
tok, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
return getKey(t.Header, keys)
})
@ -118,19 +118,33 @@ func Valid(username, token string, keys []map[string]interface{}) ([]string, map
if !ok || sub != username {
return nil, nil, ErrUnexpectedSub
}
aud, ok := claims["aud"]
var res []string
if ok {
switch aud := aud.(type) {
var aud []string
if a, ok := claims["aud"]; ok && a != nil {
switch a := a.(type) {
case string:
res = []string{aud}
aud = []string{a}
case []string:
res = aud
aud = a
}
}
perms, ok := claims["permissions"].(map[string]interface{})
var perms []string
if p, ok := claims["permissions"]; ok && p != nil {
pp, ok := p.([]interface{})
if !ok {
return nil, nil, errors.New("invalid 'permissions' field")
return nil, nil,
errors.New("invalid 'permissions' field")
}
return res, perms, nil
perms = make([]string, len(pp))
for i, v := range pp {
w, ok := v.(string)
if !ok {
return nil, nil,
errors.New("invalid 'permissions' field")
}
perms[i] = w
}
}
return aud, perms, nil
}

View file

@ -58,13 +58,7 @@ func TestES256(t *testing.T) {
}
func TestValid(t *testing.T) {
key := `{
"kty":"EC",
"alg":"ES256",
"crv":"P-256",
"x":"CBo2DHISffe8bVr6bNspCiHK3zK9pfMGfWtpHnk9-Lw",
"y":"sD5dQ-bJu8AfRGLfA6MigQyUIOQHcYx6HQOdfIbLjHo"
}`
key := `{"alg":"HS256","k":"H7pCkktUl5KyPCZ7CKw09y1j460tfIv4dRcS1XstUKY","key_ops":["sign","verify"],"kty":"oct"}`
var k map[string]interface{}
err := json.Unmarshal([]byte(key), &k)
if err != nil {
@ -73,7 +67,7 @@ func TestValid(t *testing.T) {
keys := []map[string]interface{}{k}
goodToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6eyJwcmVzZW50Ijp0cnVlfSwiaWF0IjoxNjQ1MTk1MzkxLCJleHAiOjIyNzU5MTUzOTEsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6MTIzNC8ifQ.PMgfwYwSLSFIfcNJdOEfHEZ41HM2CzbATuS1fTxncbaGyX-xXq7d9V04enXpLOMGnAlsZpOJvd7eJN2mngJMAg"
goodToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDI5NCwiZXhwIjoyOTA2NzUwMjk0LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0.6xXpgBkBMn4PSBpnwYHb-gRn_Q97Yq9DoKkAf2_6iwc"
aud, perms, err := Valid("john", goodToken, keys)
@ -83,9 +77,7 @@ func TestValid(t *testing.T) {
if !reflect.DeepEqual(aud, []string{"https://galene.org:8443/group/auth/"}) {
t.Errorf("Unexpected aud: %v", aud)
}
if !reflect.DeepEqual(
perms, map[string]interface{}{"present": true},
) {
if !reflect.DeepEqual(perms, []string{"present"}) {
t.Errorf("Unexpected perms: %v", perms)
}
}
@ -95,7 +87,7 @@ func TestValid(t *testing.T) {
t.Errorf("Token should have bad username")
}
badToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6eyJwcmVzZW50Ijp0cnVlfSwiaWF0IjoxNjQ1MTk2MDE5LCJleHAiOjIyNjAzNjQwMTksImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6MTIzNC8ifQ.4TN5zxzuKeNIw0rX0yirEkVYF1d0FHI_Lezmsa27ayi0R4ocSgTZ3q2bmlACXvyuoBqEEbuP4e77BUbGCHmpSg"
badToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDQ2OSwiZXhwIjoyOTA2NzUwNDY5LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0."
_, _, err = Valid("john", badToken, keys)
@ -104,7 +96,7 @@ func TestValid(t *testing.T) {
t.Errorf("Token should fail")
}
expiredToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6eyJwcmVzZW50Ijp0cnVlfSwiaWF0IjoxNjQ1MTk1NTY3LCJleHAiOjE2NDUxOTU1OTcsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6MTIzNC8ifQ.GXcLeyNVr5cnZjIECENyjMLH1HyNKWKkHMc9onvqA_RVYMyDLeeR_3NKH9Y7eKSXWC8jhatDWtH7Ed3KdsSxAA"
expiredToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDMyMiwiZXhwIjoxNjQ1MzEwMzUyLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0.jyqRhoV6iK54SvlP33Fy630aDo-sLNmKKi1kcfqs378"
_, _, err = Valid("john", expiredToken, keys)
@ -112,8 +104,7 @@ func TestValid(t *testing.T) {
t.Errorf("Token should be expired")
}
noneToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6eyJwcmVzZW50Ijp0cnVlfSwiaWF0IjoxNjQ1MTk1NzgyLCJleHAiOjIyNjAzNjM3ODIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6MTIzNC8ifQ."
noneToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDQwMSwiZXhwIjoxNjQ1MzEwNDMxLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0."
_, _, err = Valid("john", noneToken, keys)
if err == nil {
t.Errorf("Unsigned token should fail")

View file

@ -592,7 +592,16 @@ func checkGroupPermissions(w http.ResponseWriter, r *http.Request, groupname str
Password: pass,
},
)
if err != nil || !p.Record {
record := false
if err == nil {
for _, v := range p {
if v == "record" {
record = true
break
}
}
}
if err != nil || !record {
if err == group.ErrNotAuthorised {
time.Sleep(200 * time.Millisecond)
}