github.com/blixtra/rkt@v0.8.1-0.20160204105720-ab0d1add1a43/rkt/config/auth.go (about)

     1  // Copyright 2015 The rkt Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package config
    16  
    17  import (
    18  	"encoding/base64"
    19  	"encoding/json"
    20  	"fmt"
    21  	"net/http"
    22  )
    23  
    24  const (
    25  	authHeader string = "Authorization"
    26  )
    27  
    28  type authV1JsonParser struct{}
    29  
    30  type authV1 struct {
    31  	Domains     []string        `json:"domains"`
    32  	Type        string          `json:"type"`
    33  	Credentials json.RawMessage `json:"credentials"`
    34  }
    35  
    36  type basicV1 struct {
    37  	User     string `json:"user"`
    38  	Password string `json:"password"`
    39  }
    40  
    41  type oauthV1 struct {
    42  	Token string `json:"token"`
    43  }
    44  
    45  type dockerAuthV1JsonParser struct{}
    46  
    47  type dockerAuthV1 struct {
    48  	Registries  []string `json:"registries"`
    49  	Credentials basicV1  `json:"credentials"`
    50  }
    51  
    52  func init() {
    53  	addParser("auth", "v1", &authV1JsonParser{})
    54  	addParser("dockerAuth", "v1", &dockerAuthV1JsonParser{})
    55  	registerSubDir("auth.d", []string{"auth", "dockerAuth"})
    56  }
    57  
    58  type basicAuthHeaderer struct {
    59  	user     string
    60  	password string
    61  }
    62  
    63  func (h *basicAuthHeaderer) Header() http.Header {
    64  	headers := make(http.Header)
    65  	creds := []byte(fmt.Sprintf("%s:%s", h.user, h.password))
    66  	encodedCreds := base64.StdEncoding.EncodeToString(creds)
    67  	headers.Add(authHeader, "Basic "+encodedCreds)
    68  
    69  	return headers
    70  }
    71  
    72  type oAuthBearerTokenHeaderer struct {
    73  	token string
    74  }
    75  
    76  func (h *oAuthBearerTokenHeaderer) Header() http.Header {
    77  	headers := make(http.Header)
    78  	headers.Add(authHeader, "Bearer "+h.token)
    79  
    80  	return headers
    81  }
    82  
    83  func (p *authV1JsonParser) parse(config *Config, raw []byte) error {
    84  	var auth authV1
    85  	if err := json.Unmarshal(raw, &auth); err != nil {
    86  		return err
    87  	}
    88  	if len(auth.Domains) == 0 {
    89  		return fmt.Errorf("no domains specified")
    90  	}
    91  	if len(auth.Type) == 0 {
    92  		return fmt.Errorf("no auth type specified")
    93  	}
    94  	var (
    95  		err      error
    96  		headerer Headerer
    97  	)
    98  	switch auth.Type {
    99  	case "basic":
   100  		headerer, err = p.getBasicV1Headerer(auth.Credentials)
   101  	case "oauth":
   102  		headerer, err = p.getOAuthV1Headerer(auth.Credentials)
   103  	default:
   104  		err = fmt.Errorf("unknown auth type: %q", auth.Type)
   105  	}
   106  	if err != nil {
   107  		return err
   108  	}
   109  	for _, domain := range auth.Domains {
   110  		if _, ok := config.AuthPerHost[domain]; ok {
   111  			return fmt.Errorf("auth for domain %q is already specified", domain)
   112  		}
   113  		config.AuthPerHost[domain] = headerer
   114  	}
   115  	return nil
   116  }
   117  
   118  func (p *authV1JsonParser) getBasicV1Headerer(raw json.RawMessage) (Headerer, error) {
   119  	var basic basicV1
   120  	if err := json.Unmarshal(raw, &basic); err != nil {
   121  		return nil, err
   122  	}
   123  	if err := validateBasicV1(&basic); err != nil {
   124  		return nil, err
   125  	}
   126  	return &basicAuthHeaderer{
   127  		user:     basic.User,
   128  		password: basic.Password,
   129  	}, nil
   130  }
   131  
   132  func (p *authV1JsonParser) getOAuthV1Headerer(raw json.RawMessage) (Headerer, error) {
   133  	var oauth oauthV1
   134  	if err := json.Unmarshal(raw, &oauth); err != nil {
   135  		return nil, err
   136  	}
   137  	if len(oauth.Token) == 0 {
   138  		return nil, fmt.Errorf("no oauth bearer token specified")
   139  	}
   140  	return &oAuthBearerTokenHeaderer{
   141  		token: oauth.Token,
   142  	}, nil
   143  }
   144  
   145  func (p *dockerAuthV1JsonParser) parse(config *Config, raw []byte) error {
   146  	var auth dockerAuthV1
   147  	if err := json.Unmarshal(raw, &auth); err != nil {
   148  		return err
   149  	}
   150  	if len(auth.Registries) == 0 {
   151  		return fmt.Errorf("no registries specified")
   152  	}
   153  	if err := validateBasicV1(&auth.Credentials); err != nil {
   154  		return err
   155  	}
   156  	basic := BasicCredentials{
   157  		User:     auth.Credentials.User,
   158  		Password: auth.Credentials.Password,
   159  	}
   160  	for _, registry := range auth.Registries {
   161  		if _, ok := config.DockerCredentialsPerRegistry[registry]; ok {
   162  			return fmt.Errorf("credentials for docker registry %q are already specified", registry)
   163  		}
   164  		config.DockerCredentialsPerRegistry[registry] = basic
   165  	}
   166  	return nil
   167  }
   168  
   169  func validateBasicV1(basic *basicV1) error {
   170  	if basic == nil {
   171  		return fmt.Errorf("no credentials")
   172  	}
   173  	if len(basic.User) == 0 {
   174  		return fmt.Errorf("user not specified")
   175  	}
   176  	if len(basic.Password) == 0 {
   177  		return fmt.Errorf("password not specified")
   178  	}
   179  	return nil
   180  }