1 package wfe2 2 3 import ( 4 "fmt" 5 "net/http" 6 "strings" 7 "time" 8 9 "github.com/letsencrypt/boulder/core" 10 corepb "github.com/letsencrypt/boulder/core/proto" 11 "github.com/letsencrypt/boulder/probs" 12 "github.com/letsencrypt/boulder/web" 13 ) 14 15 // requiredStale checks if a request is a GET request with a logEvent indicating 16 // the endpoint starts with getAPIPrefix. If true then the caller is expected to 17 // apply staleness requirements via staleEnoughToGETOrder, staleEnoughToGETCert 18 // and staleEnoughToGETAuthz. 19 func requiredStale(req *http.Request, logEvent *web.RequestEvent) bool { 20 return req.Method == http.MethodGet && strings.HasPrefix(logEvent.Endpoint, getAPIPrefix) 21 } 22 23 // staleEnoughToGETOrder checks if the given order was created long enough ago 24 // in the past to be acceptably stale for accessing via the Boulder specific GET 25 // API. 26 func (wfe *WebFrontEndImpl) staleEnoughToGETOrder(order *corepb.Order) *probs.ProblemDetails { 27 return wfe.staleEnoughToGET("Order", time.Unix(0, order.CreatedNS)) 28 } 29 30 // staleEnoughToGETCert checks if the given cert was issued long enough in the 31 // past to be acceptably stale for accessing via the Boulder specific GET API. 32 func (wfe *WebFrontEndImpl) staleEnoughToGETCert(cert *corepb.Certificate) *probs.ProblemDetails { 33 return wfe.staleEnoughToGET("Certificate", time.Unix(0, cert.IssuedNS)) 34 } 35 36 // staleEnoughToGETAuthz checks if the given authorization was created long 37 // enough ago in the past to be acceptably stale for accessing via the Boulder 38 // specific GET API. Since authorization creation date is not tracked directly 39 // the appropriate lifetime for the authz is subtracted from the expiry to find 40 // the creation date. 41 func (wfe *WebFrontEndImpl) staleEnoughToGETAuthz(authzPB *corepb.Authorization) *probs.ProblemDetails { 42 // If the authorization was deactivated we cannot reliably tell what the creation date was 43 // because we can't easily tell if it was pending or finalized before deactivation. 44 // As these authorizations can no longer be used for anything, just make them immediately 45 // available for access. 46 if core.AcmeStatus(authzPB.Status) == core.StatusDeactivated { 47 return nil 48 } 49 // We don't directly track authorization creation time. Instead subtract the 50 // pendingAuthorization lifetime from the expiry. This will be inaccurate if 51 // we change the pendingAuthorizationLifetime but is sufficient for the weak 52 // staleness requirements of the GET API. 53 createdTime := time.Unix(0, authzPB.ExpiresNS).Add(-wfe.pendingAuthorizationLifetime) 54 // if the authz is valid then we need to subtract the authorizationLifetime 55 // instead of the pendingAuthorizationLifetime. 56 if core.AcmeStatus(authzPB.Status) == core.StatusValid { 57 createdTime = time.Unix(0, authzPB.ExpiresNS).Add(-wfe.authorizationLifetime) 58 } 59 return wfe.staleEnoughToGET("Authorization", createdTime) 60 } 61 62 // staleEnoughToGET checks that the createDate for the given resource is at 63 // least wfe.staleTimeout in the past. If the resource is newer than the 64 // wfe.staleTimeout then an unauthorized problem is returned. 65 func (wfe *WebFrontEndImpl) staleEnoughToGET(resourceType string, createDate time.Time) *probs.ProblemDetails { 66 if wfe.clk.Since(createDate) < wfe.staleTimeout { 67 return probs.Unauthorized(fmt.Sprintf( 68 "%s is too new for GET API. "+ 69 "You should only use this non-standard API to access resources created more than %s ago", 70 resourceType, 71 wfe.staleTimeout)) 72 } 73 return nil 74 } 75