Skip to content

Commit 7f6c878

Browse files
committed
Adjust exp argument to the duration
1 parent 0602b88 commit 7f6c878

File tree

4 files changed

+99
-10
lines changed

4 files changed

+99
-10
lines changed

auth.go

Lines changed: 46 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import (
2626
"fmt"
2727
"io/ioutil"
2828
"strings"
29+
"time"
2930

3031
"github.com/spf13/cobra"
3132

@@ -34,9 +35,10 @@ import (
3435

3536
var (
3637
cmdAuth = &cobra.Command{
37-
Use: "auth",
38-
Short: "ArangoDB authentication helper commands",
39-
Run: cmdShowUsage,
38+
Use: "auth",
39+
Short: "ArangoDB authentication helper commands",
40+
PersistentPreRunE: persistentAuthPreFunE,
41+
Run: cmdShowUsage,
4042
}
4143
cmdAuthHeader = &cobra.Command{
4244
Use: "header",
@@ -52,7 +54,8 @@ var (
5254
jwtSecretFile string
5355
user string
5456
paths []string
55-
exp int64
57+
exp string
58+
expDuration time.Duration
5659
}
5760
)
5861

@@ -65,7 +68,7 @@ func init() {
6568
pf.StringVar(&authOptions.jwtSecretFile, "auth.jwt-secret", "", "name of a plain text file containing a JWT secret used for server authentication")
6669
pf.StringVar(&authOptions.user, "auth.user", "", "name of a user to authenticate as. If empty, 'super-user' authentication is used")
6770
pf.StringSliceVar(&authOptions.paths, "auth.paths", nil, "a list of allowed pathes. The path must not include the '_db/DBNAME' prefix.")
68-
pf.Int64Var(&authOptions.exp, "auth.exp", 0, "an expiry date in seconds since epoche")
71+
pf.StringVar(&authOptions.exp, "auth.exp", "", "a time in which token should expire - based on current time in UTC. Supported units: h, m, s (default)")
6972
}
7073

7174
// mustAuthCreateJWTToken creates a the JWT token based on authentication options.
@@ -81,7 +84,7 @@ func mustAuthCreateJWTToken() string {
8184
log.Fatal().Err(err).Msgf("Failed to read JWT secret file '%s'", authOptions.jwtSecretFile)
8285
}
8386
jwtSecret := strings.TrimSpace(string(content))
84-
token, err := service.CreateJwtToken(jwtSecret, authOptions.user, "", authOptions.paths, authOptions.exp)
87+
token, err := service.CreateJwtToken(jwtSecret, authOptions.user, "", authOptions.paths, authOptions.expDuration)
8588
if err != nil {
8689
log.Fatal().Err(err).Msg("Failed to create JWT token")
8790
}
@@ -99,3 +102,40 @@ func cmdAuthTokenRun(cmd *cobra.Command, args []string) {
99102
token := mustAuthCreateJWTToken()
100103
fmt.Println(token)
101104
}
105+
106+
func persistentAuthPreFunE(cmd *cobra.Command, args []string) error {
107+
cmdMain.PersistentPreRun(cmd, args)
108+
109+
if authOptions.exp != "" {
110+
d, err := durationParser(authOptions.exp, "s")
111+
if err != nil {
112+
return err
113+
}
114+
115+
if d < 0 {
116+
return fmt.Errorf("negative duration under --auth.exp is not allowed")
117+
}
118+
119+
authOptions.expDuration = d
120+
}
121+
122+
return nil
123+
}
124+
125+
func durationParser(duration string, defaultUnit string) (time.Duration, error) {
126+
if d, err := time.ParseDuration(duration); err == nil {
127+
return d, nil
128+
} else {
129+
if !strings.HasPrefix(err.Error(), "time: missing unit in duration ") {
130+
return 0, err
131+
}
132+
133+
duration = fmt.Sprintf("%s%s", duration, defaultUnit)
134+
135+
if d, err := time.ParseDuration(duration); err == nil {
136+
return d, nil
137+
} else {
138+
return 0, err
139+
}
140+
}
141+
}

auth_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2021 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
// Author Adam Janikowski
21+
//
22+
23+
package main
24+
25+
import (
26+
"testing"
27+
28+
"github.com/stretchr/testify/require"
29+
)
30+
31+
func parseDuration(t *testing.T, in, out string) {
32+
t.Run(in, func(t *testing.T) {
33+
v, err := durationParser(in, "s")
34+
require.NoError(t, err)
35+
36+
s := v.String()
37+
38+
require.Equal(t, out, s)
39+
})
40+
}
41+
42+
func Test_Auth_DurationTest(t *testing.T) {
43+
parseDuration(t, "5", "5s")
44+
parseDuration(t, "5s", "5s")
45+
parseDuration(t, "5m", "5m0s")
46+
parseDuration(t, "5h", "5h0m0s")
47+
}

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ require (
2929
github.com/ryanuber/columnize v2.1.0+incompatible
3030
github.com/spf13/cobra v1.0.0
3131
github.com/spf13/pflag v1.0.5
32+
github.com/stretchr/testify v1.5.1
3233
github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 // indirect
3334
github.com/voxelbrain/goptions v0.0.0-20180630082107-58cddc247ea2 // indirect
3435
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9

service/authentication.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ package service
2424

2525
import (
2626
"net/http"
27+
"time"
2728

2829
jwt "github.com/dgrijalva/jwt-go"
2930
)
@@ -35,12 +36,12 @@ const (
3536

3637
// CreateJwtToken calculates a JWT authorization token based on the given secret.
3738
// If the secret is empty, an empty token is returned.
38-
func CreateJwtToken(jwtSecret, user string, serverId string, paths []string, exp int64) (string, error) {
39+
func CreateJwtToken(jwtSecret, user string, serverId string, paths []string, exp time.Duration) (string, error) {
3940
if jwtSecret == "" {
4041
return "", nil
4142
}
42-
if serverId == "" {
43-
serverId = "foo"
43+
if serverId == "" {
44+
serverId = "foo"
4445
}
4546

4647
// Create a new token object, specifying signing method and the claims
@@ -56,7 +57,7 @@ func CreateJwtToken(jwtSecret, user string, serverId string, paths []string, exp
5657
claims["allowed_paths"] = paths
5758
}
5859
if exp > 0 {
59-
claims["exp"] = exp
60+
claims["exp"] = time.Now().UTC().Add(exp).Unix()
6061
}
6162
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
6263

0 commit comments

Comments
 (0)