harbor/utils/registry/auth/handler.go

180 lines
4.3 KiB
Go
Raw Normal View History

2016-04-13 08:43:17 +02:00
/*
Copyright (c) 2016 VMware, Inc. 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 auth
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
2016-04-13 08:43:17 +02:00
"net/http"
"net/url"
"strings"
2016-04-15 07:17:32 +02:00
token_util "github.com/vmware/harbor/service/token"
2016-04-13 08:43:17 +02:00
"github.com/vmware/harbor/utils/log"
registry_errors "github.com/vmware/harbor/utils/registry/errors"
2016-04-13 08:43:17 +02:00
)
// Handler authorizes the request when encounters a 401 error
type Handler interface {
2016-04-13 09:54:29 +02:00
// Schema : basic, bearer
Schema() string
2016-04-13 08:43:17 +02:00
//AuthorizeRequest adds basic auth or token auth to the header of request
AuthorizeRequest(req *http.Request, params map[string]string) error
}
// Credential ...
type Credential struct {
// Username ...
Username string
// Password ...
Password string
2016-04-13 09:54:29 +02:00
// SecretKey ...
2016-04-13 08:43:17 +02:00
SecretKey string
}
type token struct {
Token string `json:"token"`
}
2016-04-13 09:54:29 +02:00
type standardTokenHandler struct {
2016-04-13 08:43:17 +02:00
client *http.Client
credential *Credential
}
2016-04-15 07:17:32 +02:00
// NewStandardTokenHandler returns a standard token handler. The handler will request a token
// from token server whose URL is specified in the "WWW-authentication" header and add it to
// the origin request
2016-04-13 08:43:17 +02:00
// TODO deal with https
2016-04-13 09:54:29 +02:00
func NewStandardTokenHandler(credential *Credential) Handler {
return &standardTokenHandler{
2016-04-13 08:43:17 +02:00
client: &http.Client{
Transport: http.DefaultTransport,
},
credential: credential,
}
}
2016-04-15 07:17:32 +02:00
// Schema implements the corresponding method in interface AuthHandler
2016-04-13 09:54:29 +02:00
func (t *standardTokenHandler) Schema() string {
2016-04-13 08:43:17 +02:00
return "bearer"
}
2016-04-15 07:17:32 +02:00
// AuthorizeRequest implements the corresponding method in interface AuthHandler
2016-04-13 09:54:29 +02:00
func (t *standardTokenHandler) AuthorizeRequest(req *http.Request, params map[string]string) error {
2016-04-13 08:43:17 +02:00
realm, ok := params["realm"]
if !ok {
return errors.New("no realm")
}
service := params["service"]
scope := params["scope"]
u, err := url.Parse(realm)
if err != nil {
return err
}
q := u.Query()
q.Add("service", service)
for _, s := range strings.Split(scope, " ") {
q.Add("scope", s)
}
u.RawQuery = q.Encode()
r, err := http.NewRequest("GET", u.String(), nil)
if err != nil {
return err
}
// TODO support secretKey
2016-04-15 07:17:32 +02:00
r.SetBasicAuth(t.credential.Username, t.credential.Password)
2016-04-13 08:43:17 +02:00
resp, err := t.client.Do(r)
if err != nil {
return err
}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
2016-04-13 08:43:17 +02:00
}
if resp.StatusCode != http.StatusOK {
return registry_errors.Error{
StatusCode: resp.StatusCode,
Message: string(b),
}
}
2016-04-13 08:43:17 +02:00
decoder := json.NewDecoder(resp.Body)
tk := &token{}
if err = decoder.Decode(tk); err != nil {
return err
}
req.Header.Add(http.CanonicalHeaderKey("Authorization"), fmt.Sprintf("Bearer %s", tk.Token))
2016-04-13 09:54:29 +02:00
log.Debugf("standardTokenHandler generated token successfully | %s %s", req.Method, req.URL)
return nil
}
2016-04-15 07:17:32 +02:00
type usernameTokenHandler struct {
username string
2016-04-13 09:54:29 +02:00
}
2016-04-15 07:17:32 +02:00
// NewUsernameTokenHandler returns a handler which will generate
// a token according the user's privileges
func NewUsernameTokenHandler(username string) Handler {
return &usernameTokenHandler{
username: username,
2016-04-13 09:54:29 +02:00
}
}
2016-04-15 07:17:32 +02:00
// Schema implements the corresponding method in interface AuthHandler
func (u *usernameTokenHandler) Schema() string {
2016-04-13 09:54:29 +02:00
return "bearer"
}
2016-04-15 07:17:32 +02:00
// AuthorizeRequest implements the corresponding method in interface AuthHandler
func (u *usernameTokenHandler) AuthorizeRequest(req *http.Request, params map[string]string) error {
2016-04-13 09:54:29 +02:00
service := params["service"]
scopes := []string{}
scope := params["scope"]
if len(scope) != 0 {
scopes = strings.Split(scope, " ")
}
2016-04-15 07:17:32 +02:00
token, err := token_util.GenTokenForUI(u.username, service, scopes)
2016-04-13 09:54:29 +02:00
if err != nil {
return err
}
req.Header.Add(http.CanonicalHeaderKey("Authorization"), fmt.Sprintf("Bearer %s", token))
2016-04-15 07:17:32 +02:00
log.Debugf("usernameTokenHandler generated token successfully | %s %s", req.Method, req.URL)
2016-04-13 08:43:17 +02:00
return nil
}