Middleware implements the middleware interface
(next http.Handler)
| 94 | |
| 95 | // Middleware implements the middleware interface |
| 96 | func (amw *agentMiddleware) Middleware(next http.Handler) http.Handler { |
| 97 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 98 | ctx := r.Context() |
| 99 | authorizationHeader := r.Header.Get("authorization") |
| 100 | if authorizationHeader == "" { |
| 101 | slog.InfoContext(ctx, "authorization header was empty") |
| 102 | invalidAuthResponse(ctx, w) |
| 103 | return |
| 104 | } |
| 105 | |
| 106 | bearerToken := strings.Split(authorizationHeader, " ") |
| 107 | if len(bearerToken) != 2 { |
| 108 | slog.InfoContext(ctx, "invalid authorization header") |
| 109 | invalidAuthResponse(ctx, w) |
| 110 | return |
| 111 | } |
| 112 | |
| 113 | claims := &InstanceJWTClaims{} |
| 114 | token, err := jwt.ParseWithClaims(bearerToken[1], claims, func(token *jwt.Token) (interface{}, error) { |
| 115 | if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { |
| 116 | return nil, fmt.Errorf("invalid signing method") |
| 117 | } |
| 118 | return []byte(amw.cfg.Secret), nil |
| 119 | }) |
| 120 | if err != nil { |
| 121 | slog.InfoContext(ctx, "failed to validate JWT token", "error", err) |
| 122 | invalidAuthResponse(ctx, w) |
| 123 | return |
| 124 | } |
| 125 | |
| 126 | if !claims.IsAgent { |
| 127 | invalidAuthResponse(ctx, w) |
| 128 | return |
| 129 | } |
| 130 | |
| 131 | if !token.Valid { |
| 132 | slog.InfoContext(ctx, "JWT token is invalid") |
| 133 | invalidAuthResponse(ctx, w) |
| 134 | return |
| 135 | } |
| 136 | |
| 137 | ctx, err = amw.claimsToContext(ctx, claims) |
| 138 | if err != nil { |
| 139 | slog.InfoContext(ctx, "failed to populate context", "error", err) |
| 140 | invalidAuthResponse(ctx, w) |
| 141 | return |
| 142 | } |
| 143 | |
| 144 | if InstanceID(ctx) == "" { |
| 145 | slog.InfoContext(ctx, "failed to find instance ID in context") |
| 146 | invalidAuthResponse(ctx, w) |
| 147 | return |
| 148 | } |
| 149 | |
| 150 | runnerStatus := InstanceRunnerStatus(ctx) |
| 151 | switch runnerStatus { |
| 152 | case params.RunnerActive, params.RunnerTerminated, params.RunnerFailed: |
| 153 | // Once a job starts to run, we can no longer trust that the JWT token was not compromised. |
nothing calls this directly
no test coverage detected