OLD | NEW |
1 // Copyright 2016 The LUCI Authors. All rights reserved. | 1 // Copyright 2016 The LUCI Authors. All rights reserved. |
2 // Use of this source code is governed under the Apache License, Version 2.0 | 2 // Use of this source code is governed under the Apache License, Version 2.0 |
3 // that can be found in the LICENSE file. | 3 // that can be found in the LICENSE file. |
4 | 4 |
5 package certconfig | 5 package certconfig |
6 | 6 |
7 import ( | 7 import ( |
8 "crypto/x509" | 8 "crypto/x509" |
9 "fmt" | 9 "fmt" |
10 "io/ioutil" | 10 "io/ioutil" |
11 "net/http" | 11 "net/http" |
12 "time" | 12 "time" |
13 | 13 |
14 "golang.org/x/net/context" | 14 "golang.org/x/net/context" |
15 "google.golang.org/grpc" | 15 "google.golang.org/grpc" |
16 "google.golang.org/grpc/codes" | 16 "google.golang.org/grpc/codes" |
17 | 17 |
18 ds "github.com/luci/gae/service/datastore" | 18 ds "github.com/luci/gae/service/datastore" |
19 "github.com/luci/luci-go/common/clock" | 19 "github.com/luci/luci-go/common/clock" |
20 "github.com/luci/luci-go/common/errors" | 20 "github.com/luci/luci-go/common/errors" |
21 "github.com/luci/luci-go/common/logging" | 21 "github.com/luci/luci-go/common/logging" |
| 22 "github.com/luci/luci-go/common/retry/transient" |
22 "github.com/luci/luci-go/server/auth" | 23 "github.com/luci/luci-go/server/auth" |
23 | 24 |
24 "github.com/luci/luci-go/tokenserver/api/admin/v1" | 25 "github.com/luci/luci-go/tokenserver/api/admin/v1" |
25 ) | 26 ) |
26 | 27 |
27 // List of OAuth scopes to use for token sent to CRL endpoint. | 28 // List of OAuth scopes to use for token sent to CRL endpoint. |
28 var crlFetchScopes = []string{ | 29 var crlFetchScopes = []string{ |
29 "https://www.googleapis.com/auth/userinfo.email", | 30 "https://www.googleapis.com/auth/userinfo.email", |
30 } | 31 } |
31 | 32 |
(...skipping 29 matching lines...) Expand all Loading... |
61 | 62 |
62 // Fetch latest CRL blob. | 63 // Fetch latest CRL blob. |
63 logging.Infof(c, "Fetching CRL for %q from %s", ca.CN, cfg.CrlUrl) | 64 logging.Infof(c, "Fetching CRL for %q from %s", ca.CN, cfg.CrlUrl) |
64 knownETag := crl.LastFetchETag | 65 knownETag := crl.LastFetchETag |
65 if req.Force { | 66 if req.Force { |
66 knownETag = "" | 67 knownETag = "" |
67 } | 68 } |
68 fetchCtx, _ := clock.WithTimeout(c, time.Minute) | 69 fetchCtx, _ := clock.WithTimeout(c, time.Minute) |
69 crlDer, newEtag, err := fetchCRL(fetchCtx, cfg, knownETag) | 70 crlDer, newEtag, err := fetchCRL(fetchCtx, cfg, knownETag) |
70 switch { | 71 switch { |
71 » case errors.IsTransient(err): | 72 » case transient.Tag.In(err): |
72 return nil, grpc.Errorf(codes.Internal, "transient error when fe
tching CRL - %s", err) | 73 return nil, grpc.Errorf(codes.Internal, "transient error when fe
tching CRL - %s", err) |
73 case err != nil: | 74 case err != nil: |
74 return nil, grpc.Errorf(codes.Unknown, "can't fetch CRL - %s", e
rr) | 75 return nil, grpc.Errorf(codes.Unknown, "can't fetch CRL - %s", e
rr) |
75 } | 76 } |
76 | 77 |
77 // No changes? | 78 // No changes? |
78 if knownETag != "" && knownETag == newEtag { | 79 if knownETag != "" && knownETag == newEtag { |
79 logging.Infof(c, "No changes to CRL (etag is %s), skipping", kno
wnETag) | 80 logging.Infof(c, "No changes to CRL (etag is %s), skipping", kno
wnETag) |
80 } else { | 81 } else { |
81 logging.Infof(c, "Fetched CRL size is %d bytes, etag is %s", len
(crlDer), newEtag) | 82 logging.Infof(c, "Fetched CRL size is %d bytes, etag is %s", len
(crlDer), newEtag) |
82 crl, err = validateAndStoreCRL(c, crlDer, newEtag, ca, crl) | 83 crl, err = validateAndStoreCRL(c, crlDer, newEtag, ca, crl) |
83 switch { | 84 switch { |
84 » » case errors.IsTransient(err): | 85 » » case transient.Tag.In(err): |
85 return nil, grpc.Errorf(codes.Internal, "transient error
when storing CRL - %s", err) | 86 return nil, grpc.Errorf(codes.Internal, "transient error
when storing CRL - %s", err) |
86 case err != nil: | 87 case err != nil: |
87 return nil, grpc.Errorf(codes.Unknown, "bad CRL - %s", e
rr) | 88 return nil, grpc.Errorf(codes.Unknown, "bad CRL - %s", e
rr) |
88 } | 89 } |
89 } | 90 } |
90 | 91 |
91 return &admin.FetchCRLResponse{CrlStatus: crl.GetStatusProto()}, nil | 92 return &admin.FetchCRLResponse{CrlStatus: crl.GetStatusProto()}, nil |
92 } | 93 } |
93 | 94 |
94 //////////////////////////////////////////////////////////////////////////////// | 95 //////////////////////////////////////////////////////////////////////////////// |
(...skipping 18 matching lines...) Expand all Loading... |
113 req, err := http.NewRequest("GET", cfg.CrlUrl, nil) | 114 req, err := http.NewRequest("GET", cfg.CrlUrl, nil) |
114 if err != nil { | 115 if err != nil { |
115 return nil, "", err | 116 return nil, "", err |
116 } | 117 } |
117 if knownETag != "" { | 118 if knownETag != "" { |
118 req.Header.Set("If-None-Match", knownETag) | 119 req.Header.Set("If-None-Match", knownETag) |
119 } | 120 } |
120 cl := http.Client{Transport: transport} | 121 cl := http.Client{Transport: transport} |
121 resp, err := cl.Do(req) | 122 resp, err := cl.Do(req) |
122 if err != nil { | 123 if err != nil { |
123 » » return nil, "", errors.WrapTransient(err) | 124 » » return nil, "", transient.Tag.Apply(err) |
124 } | 125 } |
125 defer resp.Body.Close() | 126 defer resp.Body.Close() |
126 | 127 |
127 // Nothing new? | 128 // Nothing new? |
128 if resp.StatusCode == http.StatusNotModified { | 129 if resp.StatusCode == http.StatusNotModified { |
129 if knownETag == "" { | 130 if knownETag == "" { |
130 return nil, "", errors.New("unexpected 304 status, no et
ag header was sent") | 131 return nil, "", errors.New("unexpected 304 status, no et
ag header was sent") |
131 } | 132 } |
132 return nil, knownETag, nil | 133 return nil, knownETag, nil |
133 } | 134 } |
134 | 135 |
135 // Read the body in its entirety. | 136 // Read the body in its entirety. |
136 blob, err = ioutil.ReadAll(resp.Body) | 137 blob, err = ioutil.ReadAll(resp.Body) |
137 if err != nil { | 138 if err != nil { |
138 » » return nil, "", errors.WrapTransient(err) | 139 » » return nil, "", transient.Tag.Apply(err) |
139 } | 140 } |
140 | 141 |
141 // Transient error? | 142 // Transient error? |
142 if resp.StatusCode >= http.StatusInternalServerError { | 143 if resp.StatusCode >= http.StatusInternalServerError { |
143 logging.Warningf(c, "GET %s - HTTP %d; %q", cfg.CrlUrl, resp.Sta
tusCode, string(blob)) | 144 logging.Warningf(c, "GET %s - HTTP %d; %q", cfg.CrlUrl, resp.Sta
tusCode, string(blob)) |
144 » » return nil, "", errors.WrapTransient(fmt.Errorf("server replied
with HTTP %d", resp.StatusCode)) | 145 » » return nil, "", errors.Reason("server replied with HTTP %(code)d
"). |
| 146 » » » D("code", resp.StatusCode).Tag(transient.Tag).Err() |
145 } | 147 } |
146 | 148 |
147 // Something we don't support or expect? | 149 // Something we don't support or expect? |
148 if resp.StatusCode != http.StatusOK { | 150 if resp.StatusCode != http.StatusOK { |
149 logging.Errorf(c, "GET %s - HTTP %d; %q", cfg.CrlUrl, resp.Statu
sCode, string(blob)) | 151 logging.Errorf(c, "GET %s - HTTP %d; %q", cfg.CrlUrl, resp.Statu
sCode, string(blob)) |
150 return nil, "", fmt.Errorf("unexpected status HTTP %d", resp.Sta
tusCode) | 152 return nil, "", fmt.Errorf("unexpected status HTTP %d", resp.Sta
tusCode) |
151 } | 153 } |
152 | 154 |
153 // Good enough. | 155 // Good enough. |
154 return blob, resp.Header.Get("ETag"), nil | 156 return blob, resp.Header.Get("ETag"), nil |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
206 return err | 208 return err |
207 } | 209 } |
208 if !curCA.Ready { | 210 if !curCA.Ready { |
209 logging.Infof(c, "CA %q is ready now", curCA.CN) | 211 logging.Infof(c, "CA %q is ready now", curCA.CN) |
210 curCA.Ready = true | 212 curCA.Ready = true |
211 toPut = append(toPut, &curCA) | 213 toPut = append(toPut, &curCA) |
212 } | 214 } |
213 return ds.Put(c, toPut) | 215 return ds.Put(c, toPut) |
214 }, nil) | 216 }, nil) |
215 if err != nil { | 217 if err != nil { |
216 » » return nil, errors.WrapTransient(err) | 218 » » return nil, transient.Tag.Apply(err) |
217 } | 219 } |
218 | 220 |
219 logging.Infof(c, "CRL for %q is updated, entity version is %d", ca.CN, u
pdated.EntityVersion) | 221 logging.Infof(c, "CRL for %q is updated, entity version is %d", ca.CN, u
pdated.EntityVersion) |
220 return updated, nil | 222 return updated, nil |
221 } | 223 } |
OLD | NEW |