mirror of
https://github.com/jech/galene.git
synced 2024-11-22 08:35:57 +01:00
Set the username in the server when using tokens.
This avoids the need to pass the username in the URL without requiring the client to parse tokens.
This commit is contained in:
parent
c4d46d20aa
commit
de3a016f4d
11 changed files with 90 additions and 64 deletions
|
@ -117,8 +117,8 @@ The `join` message requests that the sender join or leave a group:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
If token-based authorisation is beling used, then the `password` field is
|
If token-based authorisation is beling used, then the `username` and
|
||||||
omitted, and a `token` field is included instead.
|
`password` fields are omitted, and a `token` field is included instead.
|
||||||
|
|
||||||
When the sender has effectively joined the group, the peer will send
|
When the sender has effectively joined the group, the peer will send
|
||||||
a 'joined' message of kind 'join'; it may then send a 'joined' message of
|
a 'joined' message of kind 'join'; it may then send a 'joined' message of
|
||||||
|
@ -138,10 +138,11 @@ its permissions or in the recommended RTC configuration.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `permissions` field is an array of strings that may contain the values
|
The `username` field is the username that the server assigned to this
|
||||||
`present`, `op` and `record`. The `status` field is a dictionary that
|
user. The `permissions` field is an array of strings that may contain the
|
||||||
contains status information about the group, in the same format as at the
|
values `present`, `op` and `record`. The `status` field is a dictionary
|
||||||
`.status.json` URL above.
|
that contains status information about the group, in the same format as at
|
||||||
|
the `.status.json` URL above.
|
||||||
|
|
||||||
## Maintaining group membership
|
## Maintaining group membership
|
||||||
|
|
||||||
|
@ -366,13 +367,24 @@ Currently defined kinds include `clearchat` (not to be confused with the
|
||||||
|
|
||||||
# Authorisation protocol
|
# Authorisation protocol
|
||||||
|
|
||||||
|
In addition to username/password authentication, Galene supports
|
||||||
|
authentication using cryptographic tokens. Two flows are supported: using
|
||||||
|
an authentication server, where Galene's client requests a token from
|
||||||
|
a third-party server, and using an authentication portal, where
|
||||||
|
a third-party login portal redirects the user to Galene. Authentication
|
||||||
|
servers are somewhat simpler to implement, but authentication portals are
|
||||||
|
more flexible and avoid communicating the user's password to Galene's
|
||||||
|
Javascript code.
|
||||||
|
|
||||||
|
## Authentication server
|
||||||
|
|
||||||
If a group's status dictionary has a non-empty `authServer` field, then
|
If a group's status dictionary has a non-empty `authServer` field, then
|
||||||
the group uses token authentication. Before joining, the client sends
|
the group uses an authentication server. Before joining, the client sends
|
||||||
a POST request to the authorisation server URL containing in its body
|
a POST request to the authorisation server URL containing in its body
|
||||||
a JSON dictionary of the following form:
|
a JSON dictionary of the following form:
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
"location": "https://galene.example.org/group/groupname",
|
"location": "https://galene.example.org/group/groupname/",
|
||||||
"username": username,
|
"username": username,
|
||||||
"password": password
|
"password": password
|
||||||
}
|
}
|
||||||
|
@ -384,7 +396,7 @@ allowed to join, then the authorisation server replies with a signed JWT
|
||||||
```javascript
|
```javascript
|
||||||
{
|
{
|
||||||
"sub": username,
|
"sub": username,
|
||||||
"aud": "https://galene.example.org/group/groupname",
|
"aud": "https://galene.example.org/group/groupname/",
|
||||||
"permissions": ["present"],
|
"permissions": ["present"],
|
||||||
"iat": now,
|
"iat": now,
|
||||||
"exp": now + 30s,
|
"exp": now + 30s,
|
||||||
|
@ -396,4 +408,12 @@ the same format as in the `joined` message. Since the client will only
|
||||||
use the token once, at the very beginning of the session, the tokens
|
use the token once, at the very beginning of the session, the tokens
|
||||||
issued may have a short lifetime (on the order of 30s).
|
issued may have a short lifetime (on the order of 30s).
|
||||||
|
|
||||||
|
## Authentication portal
|
||||||
|
|
||||||
|
If a group's status dictionary has a non-empty `authPortal` field, Galene
|
||||||
|
redirects the user agent to the URL indicated by `authPortal`. The
|
||||||
|
authentication portal performs authorisation, generates a token as above,
|
||||||
|
then redirects back to the group's URL with the token stores in a URL
|
||||||
|
query parameter named `token`:
|
||||||
|
|
||||||
|
https://galene.example.org/group/groupname/?token=eyJhbG...
|
||||||
|
|
|
@ -59,6 +59,10 @@ func (client *Client) Username() string {
|
||||||
return "RECORDING"
|
return "RECORDING"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (client *Client) SetUsername(string) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (client *Client) SetPermissions(perms []string) {
|
func (client *Client) SetPermissions(perms []string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,9 +100,6 @@ func main() {
|
||||||
fmt.Println(s)
|
fmt.Println(s)
|
||||||
} else {
|
} else {
|
||||||
query := url.Values{}
|
query := url.Values{}
|
||||||
if username != "" {
|
|
||||||
query.Add("username", username)
|
|
||||||
}
|
|
||||||
query.Add("token", s)
|
query.Add("token", s)
|
||||||
outURL := &url.URL{
|
outURL := &url.URL{
|
||||||
Scheme: groupURL.Scheme,
|
Scheme: groupURL.Scheme,
|
||||||
|
|
|
@ -92,6 +92,7 @@ type Client interface {
|
||||||
Group() *Group
|
Group() *Group
|
||||||
Id() string
|
Id() string
|
||||||
Username() string
|
Username() string
|
||||||
|
SetUsername(string)
|
||||||
Permissions() []string
|
Permissions() []string
|
||||||
SetPermissions([]string)
|
SetPermissions([]string)
|
||||||
Data() map[string]interface{}
|
Data() map[string]interface{}
|
||||||
|
|
|
@ -565,11 +565,12 @@ func AddClient(group string, c Client, creds ClientCredentials) (*Group, error)
|
||||||
clients := g.getClientsUnlocked(nil)
|
clients := g.getClientsUnlocked(nil)
|
||||||
|
|
||||||
if !member("system", c.Permissions()) {
|
if !member("system", c.Permissions()) {
|
||||||
perms, err := g.description.GetPermission(group, creds)
|
username, perms, err := g.description.GetPermission(group, creds)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.SetUsername(username)
|
||||||
c.SetPermissions(perms)
|
c.SetPermissions(perms)
|
||||||
|
|
||||||
if !member("op", perms) {
|
if !member("op", perms) {
|
||||||
|
@ -1078,9 +1079,9 @@ func GetDescription(name string) (*Description, error) {
|
||||||
return &desc, nil
|
return &desc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (desc *Description) GetPermission(group string, creds ClientCredentials) ([]string, error) {
|
func (desc *Description) GetPermission(group string, creds ClientCredentials) (string, []string, error) {
|
||||||
if !desc.AllowAnonymous && creds.Username == "" {
|
if !desc.AllowAnonymous && creds.Username == "" {
|
||||||
return nil, ErrAnonymousNotAuthorised
|
return "", nil, ErrAnonymousNotAuthorised
|
||||||
}
|
}
|
||||||
|
|
||||||
if creds.Token == "" {
|
if creds.Token == "" {
|
||||||
|
@ -1091,36 +1092,34 @@ func (desc *Description) GetPermission(group string, creds ClientCredentials) ([
|
||||||
if desc.AllowRecording {
|
if desc.AllowRecording {
|
||||||
p = append(p, "record")
|
p = append(p, "record")
|
||||||
}
|
}
|
||||||
return p, nil
|
return creds.Username, p, nil
|
||||||
}
|
}
|
||||||
return nil, ErrNotAuthorised
|
return "", nil, ErrNotAuthorised
|
||||||
}
|
}
|
||||||
if found, good := matchClient(group, creds, desc.Presenter); found {
|
if found, good := matchClient(group, creds, desc.Presenter); found {
|
||||||
if good {
|
if good {
|
||||||
return []string{"present"}, nil
|
return creds.Username, []string{"present"}, nil
|
||||||
}
|
}
|
||||||
return nil, ErrNotAuthorised
|
return "", nil, ErrNotAuthorised
|
||||||
}
|
}
|
||||||
if found, good := matchClient(group, creds, desc.Other); found {
|
if found, good := matchClient(group, creds, desc.Other); found {
|
||||||
if good {
|
if good {
|
||||||
return nil, nil
|
return creds.Username, nil, nil
|
||||||
}
|
}
|
||||||
return nil, ErrNotAuthorised
|
return "", nil, ErrNotAuthorised
|
||||||
}
|
}
|
||||||
return nil, ErrNotAuthorised
|
return "", nil, ErrNotAuthorised
|
||||||
}
|
}
|
||||||
|
|
||||||
aud, perms, err := token.Valid(
|
sub, aud, perms, err := token.Valid(creds.Token, desc.AuthKeys)
|
||||||
creds.Username, creds.Token, desc.AuthKeys,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Token authentication: %v", err)
|
log.Printf("Token authentication: %v", err)
|
||||||
return nil, ErrNotAuthorised
|
return "", nil, ErrNotAuthorised
|
||||||
}
|
}
|
||||||
conf, err := GetConfiguration()
|
conf, err := GetConfiguration()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Read config.json: %v", err)
|
log.Printf("Read config.json: %v", err)
|
||||||
return nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
ok := false
|
ok := false
|
||||||
for _, u := range aud {
|
for _, u := range aud {
|
||||||
|
@ -1145,9 +1144,9 @@ func (desc *Description) GetPermission(group string, creds ClientCredentials) ([
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, ErrNotAuthorised
|
return "", nil, ErrNotAuthorised
|
||||||
}
|
}
|
||||||
return perms, nil
|
return sub, perms, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Status struct {
|
type Status struct {
|
||||||
|
|
|
@ -167,7 +167,7 @@ func TestPermissions(t *testing.T) {
|
||||||
|
|
||||||
for _, c := range badClients {
|
for _, c := range badClients {
|
||||||
t.Run("bad "+c.Username, func(t *testing.T) {
|
t.Run("bad "+c.Username, func(t *testing.T) {
|
||||||
p, err := d.GetPermission("test", c)
|
_, p, err := d.GetPermission("test", c)
|
||||||
if err != ErrNotAuthorised {
|
if err != ErrNotAuthorised {
|
||||||
t.Errorf("GetPermission %v: %v %v", c, err, p)
|
t.Errorf("GetPermission %v: %v %v", c, err, p)
|
||||||
}
|
}
|
||||||
|
@ -176,12 +176,13 @@ func TestPermissions(t *testing.T) {
|
||||||
|
|
||||||
for _, cp := range goodClients {
|
for _, cp := range goodClients {
|
||||||
t.Run("good "+cp.c.Username, func(t *testing.T) {
|
t.Run("good "+cp.c.Username, func(t *testing.T) {
|
||||||
p, err := d.GetPermission("test", cp.c)
|
u, p, err := d.GetPermission("test", cp.c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("GetPermission %v: %v", cp.c, err)
|
t.Errorf("GetPermission %v: %v", cp.c, err)
|
||||||
} else if !reflect.DeepEqual(p, cp.p) {
|
} else if u != cp.c.Username ||
|
||||||
t.Errorf("%v: got %v, expected %v",
|
!reflect.DeepEqual(p, cp.p) {
|
||||||
cp.c, p, cp.p)
|
t.Errorf("%v: got %v %v, expected %v",
|
||||||
|
cp.c, u, p, cp.p)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,10 @@ func (c *webClient) Username() string {
|
||||||
return c.username
|
return c.username
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *webClient) SetUsername(username string) {
|
||||||
|
c.username = username
|
||||||
|
}
|
||||||
|
|
||||||
func (c *webClient) Permissions() []string {
|
func (c *webClient) Permissions() []string {
|
||||||
return c.permissions
|
return c.permissions
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,9 +29,6 @@ let serverConnection;
|
||||||
/** @type {Object} */
|
/** @type {Object} */
|
||||||
let groupStatus = {};
|
let groupStatus = {};
|
||||||
|
|
||||||
/** @type {string} */
|
|
||||||
let username = null;
|
|
||||||
|
|
||||||
/** @type {string} */
|
/** @type {string} */
|
||||||
let token = null;
|
let token = null;
|
||||||
|
|
||||||
|
@ -273,8 +270,11 @@ function setConnected(connected) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @this {ServerConnection} */
|
/**
|
||||||
async function gotConnected() {
|
* @this {ServerConnection}
|
||||||
|
* @param {string} [username]
|
||||||
|
*/
|
||||||
|
async function gotConnected(username) {
|
||||||
let credentials;
|
let credentials;
|
||||||
if(token) {
|
if(token) {
|
||||||
credentials = {
|
credentials = {
|
||||||
|
@ -283,9 +283,9 @@ async function gotConnected() {
|
||||||
};
|
};
|
||||||
token = null;
|
token = null;
|
||||||
} else {
|
} else {
|
||||||
username = getInputElement('username').value.trim();
|
|
||||||
setConnected(true);
|
setConnected(true);
|
||||||
|
|
||||||
|
username = getInputElement('username').value.trim();
|
||||||
let pw = getInputElement('password').value;
|
let pw = getInputElement('password').value;
|
||||||
getInputElement('password').value = '';
|
getInputElement('password').value = '';
|
||||||
if(!groupStatus.authServer)
|
if(!groupStatus.authServer)
|
||||||
|
@ -2139,7 +2139,7 @@ function gotUser(id, kind) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function displayUsername() {
|
function displayUsername() {
|
||||||
document.getElementById('userspan').textContent = username;
|
document.getElementById('userspan').textContent = serverConnection.username;
|
||||||
let op = serverConnection.permissions.indexOf('op') >= 0;
|
let op = serverConnection.permissions.indexOf('op') >= 0;
|
||||||
let present = serverConnection.permissions.indexOf('present') >= 0;
|
let present = serverConnection.permissions.indexOf('present') >= 0;
|
||||||
let text = '';
|
let text = '';
|
||||||
|
@ -3776,7 +3776,6 @@ async function start() {
|
||||||
setMediaChoices(false).then(e => reflectSettings());
|
setMediaChoices(false).then(e => reflectSettings());
|
||||||
|
|
||||||
if(parms.has('token')) {
|
if(parms.has('token')) {
|
||||||
username = parms.get('username');
|
|
||||||
token = parms.get('token');
|
token = parms.get('token');
|
||||||
await serverConnect();
|
await serverConnect();
|
||||||
} else if(groupStatus.authPortal) {
|
} else if(groupStatus.authPortal) {
|
||||||
|
|
|
@ -10,8 +10,6 @@ import (
|
||||||
"github.com/golang-jwt/jwt/v4"
|
"github.com/golang-jwt/jwt/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrUnexpectedSub = errors.New("unexpected 'sub' field")
|
|
||||||
|
|
||||||
func parseBase64(k string, d map[string]interface{}) ([]byte, error) {
|
func parseBase64(k string, d map[string]interface{}) ([]byte, error) {
|
||||||
v, ok := d[k].(string)
|
v, ok := d[k].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -117,18 +115,23 @@ func toStringArray(a []interface{}) ([]string, bool) {
|
||||||
return b, true
|
return b, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func Valid(username, token string, keys []map[string]interface{}) ([]string, []string, error) {
|
func Valid(token string, keys []map[string]interface{}) (string, []string, []string, error) {
|
||||||
tok, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
|
tok, err := jwt.Parse(token, func(t *jwt.Token) (interface{}, error) {
|
||||||
return getKey(t.Header, keys)
|
return getKey(t.Header, keys)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return "", nil, nil, err
|
||||||
}
|
}
|
||||||
claims := tok.Claims.(jwt.MapClaims)
|
claims := tok.Claims.(jwt.MapClaims)
|
||||||
|
|
||||||
sub, ok := claims["sub"].(string)
|
var sub string
|
||||||
if !ok || sub != username {
|
if s, ok := claims["sub"]; ok && s != nil {
|
||||||
return nil, nil, ErrUnexpectedSub
|
ss, ok := s.(string)
|
||||||
|
if !ok {
|
||||||
|
return "", nil, nil,
|
||||||
|
errors.New("invalid 'sub' field")
|
||||||
|
}
|
||||||
|
sub = ss
|
||||||
}
|
}
|
||||||
|
|
||||||
var aud []string
|
var aud []string
|
||||||
|
@ -139,11 +142,11 @@ func Valid(username, token string, keys []map[string]interface{}) ([]string, []s
|
||||||
case []interface{}:
|
case []interface{}:
|
||||||
aud, ok = toStringArray(a)
|
aud, ok = toStringArray(a)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, nil,
|
return "", nil, nil,
|
||||||
errors.New("invalid 'aud' field")
|
errors.New("invalid 'aud' field")
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return nil, nil,
|
return "", nil, nil,
|
||||||
errors.New("invalid 'aud' field")
|
errors.New("invalid 'aud' field")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,14 +155,14 @@ func Valid(username, token string, keys []map[string]interface{}) ([]string, []s
|
||||||
if p, ok := claims["permissions"]; ok && p != nil {
|
if p, ok := claims["permissions"]; ok && p != nil {
|
||||||
pp, ok := p.([]interface{})
|
pp, ok := p.([]interface{})
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, nil,
|
return "", nil, nil,
|
||||||
errors.New("invalid 'permissions' field")
|
errors.New("invalid 'permissions' field")
|
||||||
}
|
}
|
||||||
perms, ok = toStringArray(pp)
|
perms, ok = toStringArray(pp)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, nil,
|
return "", nil, nil,
|
||||||
errors.New("invalid 'permissions' field")
|
errors.New("invalid 'permissions' field")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return aud, perms, nil
|
return sub, aud, perms, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,11 +69,14 @@ func TestValid(t *testing.T) {
|
||||||
|
|
||||||
goodToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDI5NCwiZXhwIjoyOTA2NzUwMjk0LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0.6xXpgBkBMn4PSBpnwYHb-gRn_Q97Yq9DoKkAf2_6iwc"
|
goodToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDI5NCwiZXhwIjoyOTA2NzUwMjk0LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0.6xXpgBkBMn4PSBpnwYHb-gRn_Q97Yq9DoKkAf2_6iwc"
|
||||||
|
|
||||||
aud, perms, err := Valid("john", goodToken, keys)
|
sub, aud, perms, err := Valid(goodToken, keys)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Token invalid: %v", err)
|
t.Errorf("Token invalid: %v", err)
|
||||||
} else {
|
} else {
|
||||||
|
if sub != "john" {
|
||||||
|
t.Errorf("Unexpected sub: %v", sub)
|
||||||
|
}
|
||||||
if !reflect.DeepEqual(aud, []string{"https://galene.org:8443/group/auth/"}) {
|
if !reflect.DeepEqual(aud, []string{"https://galene.org:8443/group/auth/"}) {
|
||||||
t.Errorf("Unexpected aud: %v", aud)
|
t.Errorf("Unexpected aud: %v", aud)
|
||||||
}
|
}
|
||||||
|
@ -82,14 +85,9 @@ func TestValid(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
aud, perms, err = Valid("jack", goodToken, keys)
|
|
||||||
if err != ErrUnexpectedSub {
|
|
||||||
t.Errorf("Token should have bad username")
|
|
||||||
}
|
|
||||||
|
|
||||||
badToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDQ2OSwiZXhwIjoyOTA2NzUwNDY5LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0."
|
badToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDQ2OSwiZXhwIjoyOTA2NzUwNDY5LCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0."
|
||||||
|
|
||||||
_, _, err = Valid("john", badToken, keys)
|
_, _, _, err = Valid(badToken, keys)
|
||||||
|
|
||||||
var verr *jwt.ValidationError
|
var verr *jwt.ValidationError
|
||||||
if !errors.As(err, &verr) {
|
if !errors.As(err, &verr) {
|
||||||
|
@ -98,14 +96,14 @@ func TestValid(t *testing.T) {
|
||||||
|
|
||||||
expiredToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDMyMiwiZXhwIjoxNjQ1MzEwMzUyLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0.jyqRhoV6iK54SvlP33Fy630aDo-sLNmKKi1kcfqs378"
|
expiredToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDMyMiwiZXhwIjoxNjQ1MzEwMzUyLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0.jyqRhoV6iK54SvlP33Fy630aDo-sLNmKKi1kcfqs378"
|
||||||
|
|
||||||
_, _, err = Valid("john", expiredToken, keys)
|
_, _, _, err = Valid(expiredToken, keys)
|
||||||
|
|
||||||
if !errors.As(err, &verr) {
|
if !errors.As(err, &verr) {
|
||||||
t.Errorf("Token should be expired")
|
t.Errorf("Token should be expired")
|
||||||
}
|
}
|
||||||
|
|
||||||
noneToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDQwMSwiZXhwIjoxNjQ1MzEwNDMxLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0."
|
noneToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJub25lIn0.eyJzdWIiOiJqb2huIiwiYXVkIjoiaHR0cHM6Ly9nYWxlbmUub3JnOjg0NDMvZ3JvdXAvYXV0aC8iLCJwZXJtaXNzaW9ucyI6WyJwcmVzZW50Il0sImlhdCI6MTY0NTMxMDQwMSwiZXhwIjoxNjQ1MzEwNDMxLCJpc3MiOiJodHRwOi8vbG9jYWxob3N0OjEyMzQvIn0."
|
||||||
_, _, err = Valid("john", noneToken, keys)
|
_, _, _, err = Valid(noneToken, keys)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Unsigned token should fail")
|
t.Errorf("Unsigned token should fail")
|
||||||
}
|
}
|
||||||
|
|
|
@ -586,7 +586,7 @@ func checkGroupPermissions(w http.ResponseWriter, r *http.Request, groupname str
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
p, err := desc.GetPermission(groupname,
|
_, p, err := desc.GetPermission(groupname,
|
||||||
group.ClientCredentials{
|
group.ClientCredentials{
|
||||||
Username: user,
|
Username: user,
|
||||||
Password: pass,
|
Password: pass,
|
||||||
|
|
Loading…
Reference in a new issue