Skip to content

Commit

Permalink
Merge pull request #147 from gmgigi96/app-tokens
Browse files Browse the repository at this point in the history
Application password json implementation
  • Loading branch information
ishank011 authored May 25, 2021
2 parents e46685c + 9723e23 commit 87bdf66
Show file tree
Hide file tree
Showing 4 changed files with 818 additions and 0 deletions.
3 changes: 3 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module github.com/cs3org/reva

require (
bou.ke/monkey v1.0.2
contrib.go.opencensus.io/exporter/jaeger v0.2.1
contrib.go.opencensus.io/exporter/prometheus v0.3.0
github.com/BurntSushi/toml v0.3.1
Expand All @@ -17,6 +18,7 @@ require (
github.com/cs3org/go-cs3apis v0.0.0-20210507060801-f176760d55f4
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/eventials/go-tus v0.0.0-20200718001131-45c7ec8f5d59
github.com/gdexlab/go-render v1.0.1
github.com/go-ldap/ldap/v3 v3.3.0
github.com/go-openapi/errors v0.19.6 // indirect
github.com/go-openapi/strfmt v0.19.2 // indirect
Expand All @@ -43,6 +45,7 @@ require (
github.com/rs/cors v1.7.0
github.com/rs/zerolog v1.22.0
github.com/sciencemesh/meshdirectory-web v1.0.4
github.com/sethvargo/go-password v0.2.0
github.com/stretchr/testify v1.7.0
github.com/studio-b12/gowebdav v0.0.0-20200303150724-9380631c29a1
github.com/tus/tusd v1.1.1-0.20200416115059-9deabf9d80c2
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
bou.ke/monkey v1.0.2 h1:kWcnsrCNUatbxncxR/ThdYqbytgOIArtYWqcQLQzKLI=
bou.ke/monkey v1.0.2/go.mod h1:OqickVX3tNx6t33n1xvtTtu85YN5s6cKwVug+oHMaIA=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.40.0/go.mod h1:Tk58MuI9rbLMKlAjeO/bDnteAx7tX2gJIXw4T5Jwlro=
Expand Down Expand Up @@ -184,6 +186,8 @@ github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/gdexlab/go-render v1.0.1 h1:rxqB3vo5s4n1kF0ySmoNeSPRYkEsyHgln4jFIQY7v0U=
github.com/gdexlab/go-render v1.0.1/go.mod h1:wRi5nW2qfjiGj4mPukH4UV0IknS1cHD4VgFTmJX5JzM=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-asn1-ber/asn1-ber v1.5.1 h1:pDbRAunXzIUXfx4CB2QJFv5IuPiuoW+sWvr/Us009o8=
github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
Expand Down Expand Up @@ -965,6 +969,8 @@ github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLS
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sethgrid/pester v0.0.0-20190127155807-68a33a018ad0/go.mod h1:Ad7IjTpvzZO8Fl0vh9AzQ+j/jYZfyp2diGwI8m5q+ns=
github.com/sethvargo/go-password v0.2.0 h1:BTDl4CC/gjf/axHMaDQtw507ogrXLci6XRiLc7i/UHI=
github.com/sethvargo/go-password v0.2.0/go.mod h1:Ym4Mr9JXLBycr02MFuVQ/0JHidNetSgbzutTr3zsYXE=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk=
github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ=
Expand Down
210 changes: 210 additions & 0 deletions pkg/appauth/manager/json/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,213 @@
// or submit itself to any jurisdiction.

package json

import (
"context"
"encoding/json"
"io/ioutil"
"os"
"sync"
"time"

apppb "github.com/cs3org/go-cs3apis/cs3/auth/applications/v1beta1"
authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
typespb "github.com/cs3org/go-cs3apis/cs3/types/v1beta1"
"github.com/cs3org/reva/pkg/appauth"
"github.com/cs3org/reva/pkg/appauth/manager/registry"
"github.com/cs3org/reva/pkg/errtypes"
"github.com/cs3org/reva/pkg/user"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"github.com/sethvargo/go-password/password"
)

func init() {
registry.Register("json", New)
}

type config struct {
File string `mapstructure:"file"`
TokenStrength int `mapstructure:"token_strength"`
}

type jsonManager struct {
sync.Mutex
config *config
// map[userid][password]AppPassword
passwords map[string]map[string]*apppb.AppPassword
}

// New returns a new mgr.
func New(m map[string]interface{}) (appauth.Manager, error) {
c, err := parseConfig(m)
if err != nil {
return nil, errors.Wrap(err, "error creating a new manager")
}

c.init()

// load or create file
manager, err := loadOrCreate(c.File)
if err != nil {
return nil, errors.Wrap(err, "error loading the file containing the application passwords")
}

manager.config = c

return manager, nil
}

func (c *config) init() {
if c.File == "" {
c.File = "/var/tmp/reva/appauth.json"
}
}

func parseConfig(m map[string]interface{}) (*config, error) {
c := &config{}
if err := mapstructure.Decode(m, c); err != nil {
return nil, err
}
return c, nil
}

func loadOrCreate(file string) (*jsonManager, error) {
stat, err := os.Stat(file)
if os.IsNotExist(err) || stat.Size() == 0 {
if err = ioutil.WriteFile(file, []byte("{}"), 0644); err != nil {
return nil, errors.Wrapf(err, "error creating the file %s", file)
}
}

fd, err := os.OpenFile(file, os.O_RDONLY, 0)
if err != nil {
return nil, errors.Wrapf(err, "error opening the file %s", file)
}
defer fd.Close()

data, err := ioutil.ReadAll(fd)
if err != nil {
return nil, errors.Wrapf(err, "error reading the file %s", file)
}

m := &jsonManager{}
if err = json.Unmarshal(data, &m.passwords); err != nil {
return nil, errors.Wrapf(err, "error parsing the file %s", file)
}

if m.passwords == nil {
m.passwords = make(map[string]map[string]*apppb.AppPassword)
}

return m, nil
}

func (mgr *jsonManager) GenerateAppPassword(ctx context.Context, scope map[string]*authpb.Scope, label string, expiration *typespb.Timestamp) (*apppb.AppPassword, error) {
token, err := password.Generate(mgr.config.TokenStrength, 10, 10, false, false)
if err != nil {
return nil, errors.Wrap(err, "error creating new token")
}
userID := user.ContextMustGetUser(ctx).GetId()
ctime := now()

appPass := &apppb.AppPassword{
Password: token,
TokenScope: scope,
Label: label,
Expiration: expiration,
Ctime: ctime,
Utime: ctime,
User: userID,
}
mgr.Lock()
defer mgr.Unlock()

// check if user has some previous password
if _, ok := mgr.passwords[userID.String()]; !ok {
mgr.passwords[userID.String()] = make(map[string]*apppb.AppPassword)
}

mgr.passwords[userID.String()][token] = appPass

err = mgr.save()
if err != nil {
return nil, errors.Wrap(err, "error saving new token")
}

return appPass, nil
}

func (mgr *jsonManager) ListAppPasswords(ctx context.Context) ([]*apppb.AppPassword, error) {
userID := user.ContextMustGetUser(ctx).GetId()
mgr.Lock()
defer mgr.Unlock()
appPasswords := []*apppb.AppPassword{}
for _, pw := range mgr.passwords[userID.String()] {
appPasswords = append(appPasswords, pw)
}
return appPasswords, nil
}

func (mgr *jsonManager) InvalidateAppPassword(ctx context.Context, password string) error {
userID := user.ContextMustGetUser(ctx).GetId()
mgr.Lock()
defer mgr.Unlock()

// see if user has a list of passwords
appPasswords, ok := mgr.passwords[userID.String()]
if !ok || len(appPasswords) == 0 {
return errtypes.BadRequest("password not found")
}

if _, ok := appPasswords[password]; !ok {
return errtypes.BadRequest("password not found")
}
delete(appPasswords, password)

// if user has 0 passwords, delete user key from state map
if len(mgr.passwords[userID.String()]) == 0 {
delete(mgr.passwords, userID.String())
}

return mgr.save()
}

func (mgr *jsonManager) GetAppPassword(ctx context.Context, userID *userpb.UserId, password string) (*apppb.AppPassword, error) {
mgr.Lock()
defer mgr.Unlock()

appPassword, ok := mgr.passwords[userID.String()]
if !ok {
return nil, errtypes.BadRequest("password not found")
}

pw, ok := appPassword[password]
if !ok {
return nil, errtypes.BadRequest("password not found")
}

pw.Utime = now()
if err := mgr.save(); err != nil {
return nil, errors.Wrap(err, "error saving file")
}
return pw, nil
}

func now() *typespb.Timestamp {
return &typespb.Timestamp{Seconds: uint64(time.Now().Unix())}
}

func (mgr *jsonManager) save() error {
data, err := json.Marshal(mgr.passwords)
if err != nil {
return errors.Wrap(err, "error encoding json file")
}

if err = ioutil.WriteFile(mgr.config.File, data, 0644); err != nil {
return errors.Wrapf(err, "error writing to file %s", mgr.config.File)
}

return nil
}
Loading

0 comments on commit 87bdf66

Please sign in to comment.