Skip to content
Draft
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
420 changes: 420 additions & 0 deletions internal/http/interceptors/auth/auth.go

Large diffs are not rendered by default.

109 changes: 109 additions & 0 deletions internal/http/interceptors/auth/auth_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// 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 auth

import (
"testing"
)

func TestGetCredsForUserAgent(t *testing.T) {
type test struct {
userAgent string
userAgentMap map[string]string
availableCredentials []string
expected []string
}

tests := []*test{
// no user agent we return all available credentials
{
userAgent: "",
userAgentMap: map[string]string{},
availableCredentials: []string{"basic"},
expected: []string{"basic"},
},

// map set but user agent not in map
{
userAgent: "curl",
userAgentMap: map[string]string{"mirall": "basic"},
availableCredentials: []string{"basic", "bearer"},
expected: []string{"basic", "bearer"},
},

// no user map we return all available credentials
{
userAgent: "mirall",
userAgentMap: map[string]string{},
availableCredentials: []string{"basic"},
expected: []string{"basic"},
},

// user agent set but no mapping set we return all credentials
{
userAgent: "mirall",
userAgentMap: map[string]string{},
availableCredentials: []string{"basic"},
expected: []string{"basic"},
},

// user mapping set to non available credential, we return all available
{
userAgent: "mirall",
userAgentMap: map[string]string{"mirall": "notfound"},
availableCredentials: []string{"basic", "bearer"},
expected: []string{"basic", "bearer"},
},

// user mapping set and we return only desired credential
{
userAgent: "mirall",
userAgentMap: map[string]string{"mirall": "bearer"},
availableCredentials: []string{"basic", "bearer"},
expected: []string{"bearer"},
},
}

for _, test := range tests {
got := getCredsForUserAgent(
test.userAgent,
test.userAgentMap,
test.availableCredentials)

if !match(got, test.expected) {
fail(t, got, test.expected)
}
}
}

func match(a, b []string) bool {
if len(a) != len(b) {
return false
}
for i, v := range a {
if v != b[i] {
return false
}
}
return true
}

func fail(t *testing.T, got, expected []string) {
t.Fatalf("got: %+v expected: %+v", got, expected)
}
27 changes: 27 additions & 0 deletions internal/http/interceptors/auth/credential/loader/loader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// 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 loader

import (
// Load core authentication strategies.
_ "github.com/opencloud-eu/opencloud/internal/http/interceptors/auth/credential/strategy/basic"
_ "github.com/opencloud-eu/opencloud/internal/http/interceptors/auth/credential/strategy/bearer"
_ "github.com/opencloud-eu/opencloud/internal/http/interceptors/auth/credential/strategy/ocmshares"
// Add your own here.
)
36 changes: 36 additions & 0 deletions internal/http/interceptors/auth/credential/registry/registry.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// 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 registry

import (
"github.com/opencloud-eu/reva/v2/pkg/auth"
)

// NewCredentialFunc is the function that credential strategies
// should register at init time.
type NewCredentialFunc func(map[string]interface{}) (auth.CredentialStrategy, error)

// NewCredentialFuncs is a map containing all the registered auth strategies.
var NewCredentialFuncs = map[string]NewCredentialFunc{}

// Register registers a new auth strategy new function.
// Not safe for concurrent use. Safe for use from package init.
func Register(name string, f NewCredentialFunc) {
NewCredentialFuncs[name] = f
}
56 changes: 56 additions & 0 deletions internal/http/interceptors/auth/credential/strategy/basic/basic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// 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 basic

import (
"fmt"
"net/http"

"github.com/opencloud-eu/opencloud/internal/http/interceptors/auth/credential/registry"
"github.com/opencloud-eu/reva/v2/pkg/auth"
)

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

type strategy struct{}

// New returns a new auth strategy that checks for basic auth.
// See https://tools.ietf.org/html/rfc7617
func New(m map[string]interface{}) (auth.CredentialStrategy, error) {
return &strategy{}, nil
}

func (s *strategy) GetCredentials(w http.ResponseWriter, r *http.Request) (*auth.Credentials, error) {
id, secret, ok := r.BasicAuth()
if !ok {
return nil, fmt.Errorf("no basic auth provided")
}
return &auth.Credentials{Type: "basic", ClientID: id, ClientSecret: secret}, nil
}

func (s *strategy) AddWWWAuthenticate(w http.ResponseWriter, r *http.Request, realm string) {
// TODO read realm from forwarded header?
if realm == "" {
// fall back to hostname if not configured
realm = r.Host
}
w.Header().Add("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, realm))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// 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 bearer

import (
"fmt"
"net/http"
"strings"

"github.com/opencloud-eu/opencloud/internal/http/interceptors/auth/credential/registry"
"github.com/opencloud-eu/reva/v2/pkg/auth"
)

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

type strategy struct{}

// New returns a new auth strategy that checks "Bearer" OAuth Access Tokens
// See https://tools.ietf.org/html/rfc6750#section-6.1
func New(m map[string]interface{}) (auth.CredentialStrategy, error) {
return &strategy{}, nil
}

func (s *strategy) GetCredentials(w http.ResponseWriter, r *http.Request) (*auth.Credentials, error) {
// 1. check Authorization header
hdr := r.Header.Get("Authorization")
token := strings.TrimPrefix(hdr, "Bearer ")
if token != "" {
return &auth.Credentials{Type: "bearer", ClientSecret: token}, nil
}
// TODO 2. check form encoded body parameter for POST requests, see https://tools.ietf.org/html/rfc6750#section-2.2

// 3. check uri query parameter, see https://tools.ietf.org/html/rfc6750#section-2.3
tokens, ok := r.URL.Query()["access_token"]
if !ok || len(tokens[0]) < 1 {
return nil, fmt.Errorf("no bearer auth provided")
}
return &auth.Credentials{Type: "bearer", ClientSecret: tokens[0]}, nil

}

func (s *strategy) AddWWWAuthenticate(w http.ResponseWriter, r *http.Request, realm string) {
// TODO read realm from forwarded header?
if realm == "" {
// fall back to hostname if not configured
realm = r.Host
}
w.Header().Add("WWW-Authenticate", fmt.Sprintf(`Bearer realm="%s"`, realm))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright 2018-2023 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 ocmshares

import (
"fmt"
"net/http"

"github.com/opencloud-eu/opencloud/internal/http/interceptors/auth/credential/registry"
"github.com/opencloud-eu/reva/v2/pkg/auth"
)

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

const (
headerShareToken = "ocm-token"
)

type strategy struct{}

// New returns a new auth strategy that handles public share verification.
func New(m map[string]interface{}) (auth.CredentialStrategy, error) {
return &strategy{}, nil
}

func (s *strategy) GetCredentials(w http.ResponseWriter, r *http.Request) (*auth.Credentials, error) {
token := r.Header.Get(headerShareToken)
if token == "" {
token = r.URL.Query().Get(headerShareToken)
}
if token == "" {
return nil, fmt.Errorf("no ocm token provided")
}

return &auth.Credentials{Type: "ocmshares", ClientID: token}, nil
}

func (s *strategy) AddWWWAuthenticate(w http.ResponseWriter, r *http.Request, realm string) {
// TODO read realm from forwarded header?
}
26 changes: 26 additions & 0 deletions internal/http/interceptors/auth/token/loader/loader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// 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 loader

import (
// Load core token strategies.
_ "github.com/opencloud-eu/opencloud/internal/http/interceptors/auth/token/strategy/bearer"
_ "github.com/opencloud-eu/opencloud/internal/http/interceptors/auth/token/strategy/header"
// Add your own here.
)
Loading