| 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" |
| 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 retry.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 retry.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, "", retry.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, "", retry.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(retry.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, retry.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 |