diff --git a/changelog/unreleased/token-expire-on-weekends.md b/changelog/unreleased/token-expire-on-weekends.md new file mode 100644 index 0000000000..c7a7c96e4b --- /dev/null +++ b/changelog/unreleased/token-expire-on-weekends.md @@ -0,0 +1,3 @@ +Enhancement: Expire tokens on sunday + +https://github.com/cs3org/reva/pull/3424 \ No newline at end of file diff --git a/pkg/token/manager/jwt/jwt.go b/pkg/token/manager/jwt/jwt.go index e54df4dae9..9e9b3812bd 100644 --- a/pkg/token/manager/jwt/jwt.go +++ b/pkg/token/manager/jwt/jwt.go @@ -40,8 +40,9 @@ func init() { } type config struct { - Secret string `mapstructure:"secret"` - Expires int64 `mapstructure:"expires"` + Secret string `mapstructure:"secret"` + Expires int64 `mapstructure:"expires"` + ExpiresNextWeekend bool `mapstructure:"expires_next_weekend"` } type manager struct { @@ -86,10 +87,9 @@ func New(value map[string]interface{}) (token.Manager, error) { } func (m *manager) MintToken(ctx context.Context, u *user.User, scope map[string]*auth.Scope) (string, error) { - ttl := time.Duration(m.conf.Expires) * time.Second claims := claims{ StandardClaims: jwt.StandardClaims{ - ExpiresAt: time.Now().Add(ttl).Unix(), + ExpiresAt: getExpirationDate(m.conf.ExpiresNextWeekend, time.Duration(m.conf.Expires)*time.Second).Unix(), Issuer: u.Id.Idp, Audience: "reva", IssuedAt: time.Now().Unix(), @@ -108,6 +108,22 @@ func (m *manager) MintToken(ctx context.Context, u *user.User, scope map[string] return tkn, nil } +func getExpirationDate(expiresOnNextWeekend bool, expiration time.Duration) time.Time { + if expiresOnNextWeekend { + nextWeekend := getNextWeekend(time.Now()) + return setTime(nextWeekend, 23, 59, 59) + } + return time.Now().Add(expiration) +} + +func getNextWeekend(now time.Time) time.Time { + return now.Truncate(24 * time.Hour).Add(time.Duration(7-now.Weekday()) * 24 * time.Hour) +} + +func setTime(t time.Time, hour, min, sec int) time.Time { + return time.Date(t.Year(), t.Month(), t.Day(), hour, min, sec, 0, t.Location()) +} + func (m *manager) DismantleToken(ctx context.Context, tkn string) (*user.User, map[string]*auth.Scope, error) { token, err := jwt.ParseWithClaims(tkn, &claims{}, func(token *jwt.Token) (interface{}, error) { return []byte(m.conf.Secret), nil diff --git a/pkg/token/manager/jwt/jwt_test.go b/pkg/token/manager/jwt/jwt_test.go new file mode 100644 index 0000000000..c2974b081f --- /dev/null +++ b/pkg/token/manager/jwt/jwt_test.go @@ -0,0 +1,89 @@ +// Copyright 2018-2022 CERN +// +// 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. +// +// In applying this license, CERN does not waive the privileges and immunities +// granted to it by virtue of its status as an Intergovernmental Organization +// or submit itself to any jurisdiction. + +package jwt + +import ( + "testing" + "time" +) + +func TestGetNextWeekend(t *testing.T) { + tests := []struct { + now time.Time + expected time.Time + }{ + { + now: time.Date(2022, time.December, 12, 0, 0, 0, 0, time.UTC), // mon + expected: time.Date(2022, time.December, 18, 0, 0, 0, 0, time.UTC), + }, + { + now: time.Date(2022, time.December, 13, 0, 0, 0, 0, time.UTC), // tue + expected: time.Date(2022, time.December, 18, 0, 0, 0, 0, time.UTC), + }, + { + now: time.Date(2022, time.December, 16, 0, 0, 0, 0, time.UTC), // fri + expected: time.Date(2022, time.December, 18, 0, 0, 0, 0, time.UTC), + }, + { + now: time.Date(2022, time.December, 17, 0, 0, 0, 0, time.UTC), // saturday + expected: time.Date(2022, time.December, 18, 0, 0, 0, 0, time.UTC), + }, + { + now: time.Date(2022, time.December, 18, 0, 0, 0, 0, time.UTC), // sunday + expected: time.Date(2022, time.December, 25, 0, 0, 0, 0, time.UTC), + }, + } + + for _, tt := range tests { + res := getNextWeekend(tt.now) + if !res.Equal(tt.expected) { + t.Fatalf("expected and returned result differs: expected=%s res=%s", tt.expected.String(), res.String()) + } + } +} + +func TestSetTi(t *testing.T) { + tests := []struct { + t time.Time + hour, min, sec int + expected time.Time + }{ + { + t: time.Date(2022, time.December, 12, 0, 0, 0, 0, time.UTC), + hour: 23, + min: 34, + sec: 10, + expected: time.Date(2022, time.December, 12, 23, 34, 10, 0, time.UTC), + }, + { + t: time.Date(2022, time.December, 12, 20, 19, 10, 0, time.UTC), + hour: 23, + min: 34, + sec: 10, + expected: time.Date(2022, time.December, 12, 23, 34, 10, 0, time.UTC), + }, + } + + for _, tt := range tests { + res := setTime(tt.t, tt.hour, tt.min, tt.sec) + if !res.Equal(tt.expected) { + t.Fatalf("expected and returned result differs: expected=%s res=%s", tt.expected.String(), res.String()) + } + } +}