Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Application passwords management #1719

Merged
merged 19 commits into from
May 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions changelog/unreleased/app-passwords.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Enhancement: Application passwords management

This PR adds the functionality to generate authentication tokens with limited
scope on behalf of registered users. These can be used in third party apps or in
case primary user credentials cannot be submitted to other parties.

https://github.com/cs3org/reva/pull/1719
https://github.com/cs3org/reva/issues/1714
https://github.com/cs3org/cs3apis/pull/127
1 change: 1 addition & 0 deletions cmd/revad/runtime/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
_ "github.com/cs3org/reva/internal/http/interceptors/auth/tokenwriter/loader"
_ "github.com/cs3org/reva/internal/http/interceptors/loader"
_ "github.com/cs3org/reva/internal/http/services/loader"
_ "github.com/cs3org/reva/pkg/appauth/manager/loader"
_ "github.com/cs3org/reva/pkg/auth/manager/loader"
_ "github.com/cs3org/reva/pkg/auth/registry/loader"
_ "github.com/cs3org/reva/pkg/cbox/loader"
Expand Down
5 changes: 4 additions & 1 deletion 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 @@ -14,9 +15,10 @@ require (
github.com/cheggaaa/pb v1.0.29
github.com/coreos/go-oidc v2.2.1+incompatible
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e
github.com/cs3org/go-cs3apis v0.0.0-20210507060801-f176760d55f4
github.com/cs3org/go-cs3apis v0.0.0-20210527092012-82617367e09d
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-sql-driver/mysql v1.6.0
github.com/golang/protobuf v1.5.2
Expand All @@ -41,6 +43,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
10 changes: 8 additions & 2 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 @@ -149,8 +151,8 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e h1:tqSPWQeueWTKnJVMJffz4pz0o1WuQxJ28+5x5JgaHD8=
github.com/cs3org/cato v0.0.0-20200828125504-e418fc54dd5e/go.mod h1:XJEZ3/EQuI3BXTp/6DUzFr850vlxq11I6satRtz0YQ4=
github.com/cs3org/go-cs3apis v0.0.0-20210507060801-f176760d55f4 h1:lihiUwqal+sO+57VTHGRvHbI9baN+D85fPZG2N1Sk6s=
github.com/cs3org/go-cs3apis v0.0.0-20210507060801-f176760d55f4/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/go-cs3apis v0.0.0-20210527092012-82617367e09d h1:mQiARNvWPIPdqal7gWWTIVpC6C10aC9/2fVjCK9AIg4=
github.com/cs3org/go-cs3apis v0.0.0-20210527092012-82617367e09d/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cucumber/godog v0.8.1/go.mod h1:vSh3r/lM+psC1BPXvdkSEuNjmXfpVqrMGYAElF6hxnA=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
Expand Down Expand Up @@ -193,6 +195,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/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
Expand Down Expand Up @@ -1080,6 +1084,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
9 changes: 8 additions & 1 deletion internal/grpc/interceptors/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,14 @@ func dismantleToken(ctx context.Context, tkn string, req interface{}, mgr token.
// for OCM shares, guest accounts, etc.
log.Info().Msgf("resolving path reference to ID to check token scope %+v", ref.GetPath())
var share link.PublicShare
err = utils.UnmarshalJSONToProtoV1(tokenScope["publicshare"].Resource.Value, &share)
var publicShareScope []byte
for k := range tokenScope {
if strings.HasPrefix(k, "publicshare") {
publicShareScope = tokenScope[k].Resource.Value
break
}
}
err = utils.UnmarshalJSONToProtoV1(publicShareScope, &share)
if err != nil {
return nil, err
}
Expand Down
158 changes: 158 additions & 0 deletions internal/grpc/services/applicationauth/applicationauth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
// Copyright 2018-2021 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 applicationauth

import (
"context"

appauthpb "github.com/cs3org/go-cs3apis/cs3/auth/applications/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/rgrpc"
"github.com/cs3org/reva/pkg/rgrpc/status"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"google.golang.org/grpc"
)

func init() {
rgrpc.Register("applicationauth", New)
}

type config struct {
Driver string `mapstructure:"driver"`
Drivers map[string]map[string]interface{} `mapstructure:"drivers"`
}

type service struct {
conf *config
am appauth.Manager
}

func (c *config) init() {
if c.Driver == "" {
c.Driver = "json"
}
}

func (s *service) Register(ss *grpc.Server) {
appauthpb.RegisterApplicationsAPIServer(ss, s)
}

func getAppAuthManager(c *config) (appauth.Manager, error) {
if f, ok := registry.NewFuncs[c.Driver]; ok {
return f(c.Drivers[c.Driver])
}
return nil, errtypes.NotFound("driver not found: " + c.Driver)
}

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

// New creates a app auth provider svc
func New(m map[string]interface{}, ss *grpc.Server) (rgrpc.Service, error) {

c, err := parseConfig(m)
if err != nil {
return nil, err
}
c.init()

am, err := getAppAuthManager(c)
if err != nil {
return nil, err
}

service := &service{
conf: c,
am: am,
}

return service, nil
}

func (s *service) Close() error {
return nil
}

func (s *service) UnprotectedEndpoints() []string {
return []string{"/cs3.auth.applications.v1beta1.ApplicationsAPI/GetAppPassword"}
}

func (s *service) GenerateAppPassword(ctx context.Context, req *appauthpb.GenerateAppPasswordRequest) (*appauthpb.GenerateAppPasswordResponse, error) {
pwd, err := s.am.GenerateAppPassword(ctx, req.TokenScope, req.Label, req.Expiration)
if err != nil {
return &appauthpb.GenerateAppPasswordResponse{
Status: status.NewInternal(ctx, err, "error generating app password"),
}, nil
}

return &appauthpb.GenerateAppPasswordResponse{
Status: status.NewOK(ctx),
AppPassword: pwd,
}, nil
}

func (s *service) ListAppPasswords(ctx context.Context, req *appauthpb.ListAppPasswordsRequest) (*appauthpb.ListAppPasswordsResponse, error) {
pwds, err := s.am.ListAppPasswords(ctx)
if err != nil {
return &appauthpb.ListAppPasswordsResponse{
Status: status.NewInternal(ctx, err, "error listing app passwords"),
}, nil
}

return &appauthpb.ListAppPasswordsResponse{
Status: status.NewOK(ctx),
AppPasswords: pwds,
}, nil
}

func (s *service) InvalidateAppPassword(ctx context.Context, req *appauthpb.InvalidateAppPasswordRequest) (*appauthpb.InvalidateAppPasswordResponse, error) {
err := s.am.InvalidateAppPassword(ctx, req.Password)
if err != nil {
return &appauthpb.InvalidateAppPasswordResponse{
Status: status.NewInternal(ctx, err, "error invalidating app password"),
}, nil
}

return &appauthpb.InvalidateAppPasswordResponse{
Status: status.NewOK(ctx),
}, nil
}

func (s *service) GetAppPassword(ctx context.Context, req *appauthpb.GetAppPasswordRequest) (*appauthpb.GetAppPasswordResponse, error) {
pwd, err := s.am.GetAppPassword(ctx, req.User, req.Password)
if err != nil {
return &appauthpb.GetAppPasswordResponse{
Status: status.NewInternal(ctx, err, "error getting app password via username/password"),
}, nil
}

return &appauthpb.GetAppPasswordResponse{
Status: status.NewOK(ctx),
AppPassword: pwd,
}, nil
}
96 changes: 96 additions & 0 deletions internal/grpc/services/gateway/applicationauth.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright 2018-2021 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 gateway

import (
"context"

appauthpb "github.com/cs3org/go-cs3apis/cs3/auth/applications/v1beta1"
"github.com/cs3org/reva/pkg/rgrpc/status"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
"github.com/pkg/errors"
)

func (s *svc) GenerateAppPassword(ctx context.Context, req *appauthpb.GenerateAppPasswordRequest) (*appauthpb.GenerateAppPasswordResponse, error) {
c, err := pool.GetAppAuthProviderServiceClient(s.c.ApplicationAuthEndpoint)
if err != nil {
err = errors.Wrap(err, "gateway: error calling GetAppAuthProviderServiceClient")
return &appauthpb.GenerateAppPasswordResponse{
Status: status.NewInternal(ctx, err, "error getting app auth provider client"),
}, nil
}

res, err := c.GenerateAppPassword(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling GenerateAppPassword")
}

return res, nil
}

func (s *svc) ListAppPasswords(ctx context.Context, req *appauthpb.ListAppPasswordsRequest) (*appauthpb.ListAppPasswordsResponse, error) {
c, err := pool.GetAppAuthProviderServiceClient(s.c.ApplicationAuthEndpoint)
if err != nil {
err = errors.Wrap(err, "gateway: error calling GetAppAuthProviderServiceClient")
return &appauthpb.ListAppPasswordsResponse{
Status: status.NewInternal(ctx, err, "error getting app auth provider client"),
}, nil
}

res, err := c.ListAppPasswords(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling ListAppPasswords")
}

return res, nil
}

func (s *svc) InvalidateAppPassword(ctx context.Context, req *appauthpb.InvalidateAppPasswordRequest) (*appauthpb.InvalidateAppPasswordResponse, error) {
c, err := pool.GetAppAuthProviderServiceClient(s.c.ApplicationAuthEndpoint)
if err != nil {
err = errors.Wrap(err, "gateway: error calling GetAppAuthProviderServiceClient")
return &appauthpb.InvalidateAppPasswordResponse{
Status: status.NewInternal(ctx, err, "error getting app auth provider client"),
}, nil
}

res, err := c.InvalidateAppPassword(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling InvalidateAppPassword")
}

return res, nil
}

func (s *svc) GetAppPassword(ctx context.Context, req *appauthpb.GetAppPasswordRequest) (*appauthpb.GetAppPasswordResponse, error) {
c, err := pool.GetAppAuthProviderServiceClient(s.c.ApplicationAuthEndpoint)
if err != nil {
err = errors.Wrap(err, "gateway: error calling GetAppAuthProviderServiceClient")
return &appauthpb.GetAppPasswordResponse{
Status: status.NewInternal(ctx, err, "error getting app auth provider client"),
}, nil
}

res, err := c.GetAppPassword(ctx, req)
if err != nil {
return nil, errors.Wrap(err, "gateway: error calling GetAppPassword")
}

return res, nil
}
2 changes: 2 additions & 0 deletions internal/grpc/services/gateway/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func init() {

type config struct {
AuthRegistryEndpoint string `mapstructure:"authregistrysvc"`
ApplicationAuthEndpoint string `mapstructure:"applicationauthsvc"`
StorageRegistryEndpoint string `mapstructure:"storageregistrysvc"`
AppRegistryEndpoint string `mapstructure:"appregistrysvc"`
PreferencesEndpoint string `mapstructure:"preferencessvc"`
Expand Down Expand Up @@ -84,6 +85,7 @@ func (c *config) init() {
// if services address are not specified we used the shared conf
// for the gatewaysvc to have dev setups very quickly.
c.AuthRegistryEndpoint = sharedconf.GetGatewaySVC(c.AuthRegistryEndpoint)
c.ApplicationAuthEndpoint = sharedconf.GetGatewaySVC(c.ApplicationAuthEndpoint)
c.StorageRegistryEndpoint = sharedconf.GetGatewaySVC(c.StorageRegistryEndpoint)
c.AppRegistryEndpoint = sharedconf.GetGatewaySVC(c.AppRegistryEndpoint)
c.PreferencesEndpoint = sharedconf.GetGatewaySVC(c.PreferencesEndpoint)
Expand Down
1 change: 1 addition & 0 deletions internal/grpc/services/loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package loader

import (
// Load core gRPC services.
_ "github.com/cs3org/reva/internal/grpc/services/applicationauth"
_ "github.com/cs3org/reva/internal/grpc/services/appprovider"
_ "github.com/cs3org/reva/internal/grpc/services/appregistry"
_ "github.com/cs3org/reva/internal/grpc/services/authprovider"
Expand Down
2 changes: 1 addition & 1 deletion internal/grpc/services/userprovider/userprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ func (s *service) Close() error {
}

func (s *service) UnprotectedEndpoints() []string {
return []string{"/cs3.identity.user.v1beta1.UserAPI/GetUser"}
return []string{"/cs3.identity.user.v1beta1.UserAPI/GetUser", "/cs3.identity.user.v1beta1.UserAPI/GetUserByClaim"}
}

func (s *service) Register(ss *grpc.Server) {
Expand Down
Loading