Skip to content

Commit

Permalink
Merge pull request #109 from opensds/development
Browse files Browse the repository at this point in the history
Merge development to master branch to publish Capri Milestone-2
  • Loading branch information
leonwanghui authored Mar 29, 2019
2 parents 9397b37 + 2d9c76b commit 146a9d8
Show file tree
Hide file tree
Showing 69 changed files with 2,831 additions and 365 deletions.
6 changes: 4 additions & 2 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions api/cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/opensds/multi-cloud/api/pkg/backend"
"github.com/opensds/multi-cloud/api/pkg/dataflow"
"github.com/opensds/multi-cloud/api/pkg/filters/context"
"github.com/opensds/multi-cloud/api/pkg/filters/signature/signer"
// _ "github.com/micro/go-plugins/client/grpc"
"github.com/opensds/multi-cloud/api/pkg/filters/auth"
"github.com/opensds/multi-cloud/api/pkg/filters/logging"
Expand Down Expand Up @@ -59,6 +60,7 @@ func main() {
s3ws.Consumes(restful.MIME_XML)
s3ws.Produces(restful.MIME_XML)
s3ws.Filter(logging.FilterFactory())
s3ws.Filter(signer.FilterFactory())
s3.RegisterRouter(s3ws)

wc.Add(ws)
Expand Down
1 change: 0 additions & 1 deletion api/pkg/filters/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,3 @@ func FilterFactory() restful.FilterFunction {
}
return auth.Filter
}

12 changes: 8 additions & 4 deletions api/pkg/filters/auth/keystone.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ package auth

import (
"net/http"
"time"
"strings"
"os"
"strings"
"time"

"github.com/emicklei/go-restful"
log "github.com/golang/glog"
Expand All @@ -35,6 +35,10 @@ type Keystone struct {
identity *gophercloud.ServiceClient
}

func GetIdentity(k *Keystone) *gophercloud.ServiceClient {
return k.identity
}

func NewKeystone() AuthBase {
k := &Keystone{}
if err := k.SetUp(); err != nil {
Expand All @@ -50,7 +54,7 @@ func (k *Keystone) SetUp() error {
DomainName: os.Getenv("OS_USER_DOMIN_ID"),
Username: os.Getenv("OS_USERNAME"),
Password: os.Getenv("OS_PASSWORD"),
TenantName: os.Getenv("OS_PROJECT_NAME"),
TenantName: os.Getenv("OS_PROJECT_NAME"),
}
log.Infof("opts:%v", opts)
provider, err := openstack.AuthenticatedClient(opts)
Expand All @@ -72,7 +76,7 @@ func (k *Keystone) Filter(req *restful.Request, resp *restful.Response, chain *r
// Strip the spaces around the token ctx.Input.Header(constants.AuthTokenHeader)
token := strings.TrimSpace(req.HeaderParameter(constants.AuthTokenHeader))
if err := k.validateToken(req, resp, token); err != nil {
return
return
}
chain.ProcessFilter(req, resp)
}
Expand Down
82 changes: 82 additions & 0 deletions api/pkg/filters/signature/credentials/credential.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// Copyright (c) 2019 Huawei Technologies Co., Ltd. All Rights Reserved.
//
// 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.

package credentials

import (
"sync"
)

// A Value is the OpenSDS multi-cloud credentials value.
type Value struct {
// OpenSDS multi-cloud Access key ID
AccessKeyID string

// OpenSDS multi-cloud Secret Access Key
SecretAccessKey string

// Provider used to get credentials
ProviderName string
}

// A Provider is the interface to provide credentials Value.
type Provider interface {
// Retrieve returns credential value if it successfully retrieved the value,
// otherwise returns Error.
Retrieve() (Value, error)
}

// An ErrorProvider is a credentials provider that always returns an error
type ErrorProvider struct {
// The error to be returned from Retrieve
Err error

// The provider name to set on the Retrieved returned Value
ProviderName string
}

// Retrieve will always return the error that the ErrorProvider was created with.
func (p ErrorProvider) Retrieve() (Value, error) {
return Value{ProviderName: p.ProviderName}, p.Err
}

// A Credentials provides concurrency safe retrieval of OpenSDS multi-cloud credentials Value.
type Credentials struct {
credentials Value

m sync.RWMutex

provider Provider
}

// NewCredentials returns a pointer to a new Credentials with the provider set.
func NewCredentials(provider Provider) *Credentials {
return &Credentials{
provider: provider,
}
}

// Get returns the credentials value, or error on failed retrieval
func (c *Credentials) Get() (Value, error) {

c.m.RLock()
credentials, err := c.provider.Retrieve()
if err != nil {
return Value{}, err
}
c.credentials = credentials
c.m.RUnlock()

return c.credentials, nil
}
77 changes: 77 additions & 0 deletions api/pkg/filters/signature/credentials/credential_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright (c) 2019 Huawei Technologies Co., Ltd. All Rights Reserved.
//
// 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.

package credentials

import (
"testing"
)

type mockProvider struct {
credentials Value
err error
}

func (m *mockProvider) Retrieve() (Value, error) {
m.credentials.ProviderName = "mockProvider"
return m.credentials, m.err
}

func TestCredentialsGet(t *testing.T) {
c := NewCredentials(&mockProvider{
credentials: Value{
AccessKeyID: "access_key",
SecretAccessKey: "secret_key",
},
})

creds, err := c.Get()
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if e, a := "access_key", creds.AccessKeyID; e != a {
t.Errorf("Expect access key ID to match, %v got %v", e, a)
}
if e, a := "secret_key", creds.SecretAccessKey; e != a {
t.Errorf("Expect secret access key to match, %v got %v", e, a)
}
}

func TestCredentialsGetWithProviderName(t *testing.T) {
mock := &mockProvider{}

c := NewCredentials(mock)

credentials, err := c.Get()
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if e, a := credentials.ProviderName, "mockProvider"; e != a {
t.Errorf("Expected provider name to match, %v got %v", e, a)
}
}

func TestCredentialsGetWithError(t *testing.T) {
mock := &mockProvider{}

c := NewCredentials(mock)

credentials, err := c.Get()
if err != nil {
t.Errorf("Expected no error, got %v", err)
}
if e, a := credentials.ProviderName, "mockProvider"; e != a {
t.Errorf("Expected provider name to match, %v got %v", e, a)
}
}
134 changes: 134 additions & 0 deletions api/pkg/filters/signature/credentials/keystonecredentials/provider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Copyright (c) 2019 Huawei Technologies Co., Ltd. All Rights Reserved.
//
// 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.

// Package keystonecredentials provides support for retrieving credentials from keystone

package keystonecredentials

import (
"encoding/json"
"strings"

log "github.com/golang/glog"
"github.com/gophercloud/gophercloud"
creds "github.com/gophercloud/gophercloud/openstack/identity/v3/credentials"
"github.com/opensds/multi-cloud/api/pkg/filters/auth"
"github.com/opensds/multi-cloud/api/pkg/filters/signature/credentials"
"github.com/opensds/multi-cloud/api/pkg/model"
)

// ProviderName is the name of the credentials provider.
const ProviderName = `KeystoneProvider`

// KeystoneProvider is a client to retrieve credentials from Keystone.
type KeystoneProvider struct {
// Requires a gopher cloud Client to make HTTP requests to the Keystone with.
Identity *gophercloud.ServiceClient

// Requires an AccessKeyID to filter the credentials request.
AccessKeyID string
}

type Blob struct {
Access string `json:"access"`
Secret string `json:"secret"`
}

// NewProviderClient returns a credentials Provider for retrieving credentials
func NewProviderClient(accessKeyID string, options ...func(*KeystoneProvider)) credentials.Provider {

k := &auth.Keystone{}
if err := k.SetUp(); err != nil {
// If auth set up failed, raise panic.
panic(err)
}

kp := &KeystoneProvider{
AccessKeyID: accessKeyID,
}
kp.Identity = auth.GetIdentity(k)

log.V(4).Infof("Service Token Info: %s", kp.Identity.TokenID)

return kp
}

// NewCredentialsClient returns a Credentials wrapper for retrieving credentials
func NewCredentialsClient(accessKeyID string, options ...func(*KeystoneProvider)) *credentials.Credentials {
return credentials.NewCredentials(NewProviderClient(accessKeyID,options...))
}


// Retrieve will attempt to request the credentials from the Keystone
// And error will be returned if the retrieval fails.
func (p *KeystoneProvider) Retrieve() (credentials.Value, error) {
resp, err := p.getCredentials(p.AccessKeyID)
if err != nil {
return credentials.Value{ProviderName: ProviderName}, err
}

return credentials.Value{
AccessKeyID: resp.AccessKeyID,
SecretAccessKey: resp.SecretAccessKey,
ProviderName: ProviderName,
}, nil
}

type getCredentialsOutput struct {
AccessKeyID string
SecretAccessKey string
}

// Returns AccessKey and SecretKey Values, Retrieves Credentials
// from Keystone And error will be returned if the retrieval fails.
func (p *KeystoneProvider) getCredentials(accessKeyID string) (*getCredentialsOutput, error) {

allPages, err := creds.List(p.Identity, nil).AllPages()

credentials, err := creds.ExtractCredentials(allPages)
log.V(4).Infof("Credentials: %s", credentials)

if err != nil {
return nil, err
}

blob, err := getBlob(credentials, accessKeyID)

if blob != nil{
return &getCredentialsOutput{
AccessKeyID: blob.Access,
SecretAccessKey: blob.Secret,
}, nil
}
return nil, err
}

// Returns a credential Blob for getting access and secret
// And error will be returned if it fails.
func getBlob(credentials []creds.Credential, accessKeyID string) (*Blob, error) {
blob := &Blob{}
for _, credential := range credentials{
var blobStr = credential.Blob
b := strings.Replace(blobStr,"\\", "", -1 )
err := json.Unmarshal([]byte(b), blob)

if err != nil {
return nil, err
}
if blob.Access == accessKeyID {
return blob, nil
}
}
return nil, model.NewNotFoundError("credential is missing")
}
Loading

0 comments on commit 146a9d8

Please sign in to comment.