Browse code

Get token on each request

Signed-off-by: Derek McGowan <derek@mcgstyle.net>

Derek McGowan authored on 2014/12/20 09:14:04
Showing 2 changed files
... ...
@@ -38,56 +38,70 @@ type ConfigFile struct {
38 38
 }
39 39
 
40 40
 type RequestAuthorization struct {
41
-	Token    string
42
-	Username string
43
-	Password string
41
+	authConfig       *AuthConfig
42
+	registryEndpoint *Endpoint
43
+	resource         string
44
+	scope            string
45
+	actions          []string
44 46
 }
45 47
 
46
-func NewRequestAuthorization(authConfig *AuthConfig, registryEndpoint *Endpoint, resource, scope string, actions []string) (*RequestAuthorization, error) {
47
-	var auth RequestAuthorization
48
+func NewRequestAuthorization(authConfig *AuthConfig, registryEndpoint *Endpoint, resource, scope string, actions []string) *RequestAuthorization {
49
+	return &RequestAuthorization{
50
+		authConfig:       authConfig,
51
+		registryEndpoint: registryEndpoint,
52
+		resource:         resource,
53
+		scope:            scope,
54
+		actions:          actions,
55
+	}
56
+}
48 57
 
58
+func (auth *RequestAuthorization) getToken() (string, error) {
59
+	// TODO check if already has token and before expiration
49 60
 	client := &http.Client{
50 61
 		Transport: &http.Transport{
51 62
 			DisableKeepAlives: true,
52
-			Proxy:             http.ProxyFromEnvironment,
53
-		},
63
+			Proxy:             http.ProxyFromEnvironment},
54 64
 		CheckRedirect: AddRequiredHeadersToRedirectedRequests,
55 65
 	}
56 66
 	factory := HTTPRequestFactory(nil)
57 67
 
58
-	for _, challenge := range registryEndpoint.AuthChallenges {
59
-		log.Debugf("Using %q auth challenge with params %s for %s", challenge.Scheme, challenge.Parameters, authConfig.Username)
60
-
68
+	for _, challenge := range auth.registryEndpoint.AuthChallenges {
61 69
 		switch strings.ToLower(challenge.Scheme) {
62 70
 		case "basic":
63
-			auth.Username = authConfig.Username
64
-			auth.Password = authConfig.Password
71
+			// no token necessary
65 72
 		case "bearer":
73
+			log.Debugf("Getting bearer token with %s for %s", challenge.Parameters, auth.authConfig.Username)
66 74
 			params := map[string]string{}
67 75
 			for k, v := range challenge.Parameters {
68 76
 				params[k] = v
69 77
 			}
70
-			params["scope"] = fmt.Sprintf("%s:%s:%s", resource, scope, strings.Join(actions, ","))
71
-			token, err := getToken(authConfig.Username, authConfig.Password, params, registryEndpoint, client, factory)
78
+			params["scope"] = fmt.Sprintf("%s:%s:%s", auth.resource, auth.scope, strings.Join(auth.actions, ","))
79
+			token, err := getToken(auth.authConfig.Username, auth.authConfig.Password, params, auth.registryEndpoint, client, factory)
72 80
 			if err != nil {
73
-				return nil, err
81
+				return "", err
74 82
 			}
83
+			// TODO cache token and set expiration to one minute from now
75 84
 
76
-			auth.Token = token
85
+			return token, nil
77 86
 		default:
78 87
 			log.Infof("Unsupported auth scheme: %q", challenge.Scheme)
79 88
 		}
80 89
 	}
81
-
82
-	return &auth, nil
90
+	// TODO no expiration, do not reattempt to get a token
91
+	return "", nil
83 92
 }
84 93
 
85
-func (auth *RequestAuthorization) Authorize(req *http.Request) {
86
-	if auth.Token != "" {
87
-		req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", auth.Token))
88
-	} else if auth.Username != "" && auth.Password != "" {
89
-		req.SetBasicAuth(auth.Username, auth.Password)
94
+func (auth *RequestAuthorization) Authorize(req *http.Request) error {
95
+	token, err := auth.getToken()
96
+	if err != nil {
97
+		return err
98
+	}
99
+	if token != "" {
100
+		req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token))
101
+	} else if auth.authConfig.Username != "" && auth.authConfig.Password != "" {
102
+		req.SetBasicAuth(auth.authConfig.Username, auth.authConfig.Password)
90 103
 	}
104
+	return nil
91 105
 }
92 106
 
93 107
 // create a base64 encoded auth string to store in config
... ...
@@ -42,7 +42,7 @@ func (r *Session) GetV2Authorization(imageName string, readOnly bool) (auth *Req
42 42
 	r.indexEndpoint = registry
43 43
 
44 44
 	log.Debugf("Getting authorization for %s %s", imageName, scopes)
45
-	return NewRequestAuthorization(r.GetAuthConfig(true), registry, "repository", imageName, scopes)
45
+	return NewRequestAuthorization(r.GetAuthConfig(true), registry, "repository", imageName, scopes), nil
46 46
 }
47 47
 
48 48
 //
... ...
@@ -65,7 +65,9 @@ func (r *Session) GetV2ImageManifest(imageName, tagName string, auth *RequestAut
65 65
 	if err != nil {
66 66
 		return nil, err
67 67
 	}
68
-	auth.Authorize(req)
68
+	if err := auth.Authorize(req) {
69
+		return nil, err
70
+	}
69 71
 	res, _, err := r.doRequest(req)
70 72
 	if err != nil {
71 73
 		return nil, err
... ...
@@ -103,7 +105,9 @@ func (r *Session) PostV2ImageMountBlob(imageName, sumType, sum string, auth *Req
103 103
 	if err != nil {
104 104
 		return false, err
105 105
 	}
106
-	auth.Authorize(req)
106
+	if err := auth.Authorize(req) {
107
+		return nil, err
108
+	}
107 109
 	res, _, err := r.doRequest(req)
108 110
 	if err != nil {
109 111
 		return false, err
... ...
@@ -132,7 +136,9 @@ func (r *Session) GetV2ImageBlob(imageName, sumType, sum string, blobWrtr io.Wri
132 132
 	if err != nil {
133 133
 		return err
134 134
 	}
135
-	auth.Authorize(req)
135
+	if err := auth.Authorize(req) {
136
+		return nil, err
137
+	}
136 138
 	res, _, err := r.doRequest(req)
137 139
 	if err != nil {
138 140
 		return err
... ...
@@ -161,7 +167,9 @@ func (r *Session) GetV2ImageBlobReader(imageName, sumType, sum string, auth *Req
161 161
 	if err != nil {
162 162
 		return nil, 0, err
163 163
 	}
164
-	auth.Authorize(req)
164
+	if err := auth.Authorize(req) {
165
+		return nil, err
166
+	}
165 167
 	res, _, err := r.doRequest(req)
166 168
 	if err != nil {
167 169
 		return nil, 0, err
... ...
@@ -196,7 +204,9 @@ func (r *Session) PutV2ImageBlob(imageName, sumType, sumStr string, blobRdr io.R
196 196
 		return err
197 197
 	}
198 198
 
199
-	auth.Authorize(req)
199
+	if err := auth.Authorize(req) {
200
+		return nil, err
201
+	}
200 202
 	res, _, err := r.doRequest(req)
201 203
 	if err != nil {
202 204
 		return err
... ...
@@ -212,7 +222,9 @@ func (r *Session) PutV2ImageBlob(imageName, sumType, sumStr string, blobRdr io.R
212 212
 	queryParams := url.Values{}
213 213
 	queryParams.Add("digest", sumType+":"+sumStr)
214 214
 	req.URL.RawQuery = queryParams.Encode()
215
-	auth.Authorize(req)
215
+	if err := auth.Authorize(req) {
216
+		return nil, err
217
+	}
216 218
 	res, _, err = r.doRequest(req)
217 219
 	if err != nil {
218 220
 		return err
... ...
@@ -242,7 +254,9 @@ func (r *Session) PutV2ImageManifest(imageName, tagName string, manifestRdr io.R
242 242
 	if err != nil {
243 243
 		return err
244 244
 	}
245
-	auth.Authorize(req)
245
+	if err := auth.Authorize(req) {
246
+		return nil, err
247
+	}
246 248
 	res, _, err := r.doRequest(req)
247 249
 	if err != nil {
248 250
 		return err
... ...
@@ -274,7 +288,9 @@ func (r *Session) GetV2RemoteTags(imageName string, auth *RequestAuthorization)
274 274
 	if err != nil {
275 275
 		return nil, err
276 276
 	}
277
-	auth.Authorize(req)
277
+	if err := auth.Authorize(req) {
278
+		return nil, err
279
+	}
278 280
 	res, _, err := r.doRequest(req)
279 281
 	if err != nil {
280 282
 		return nil, err