diff --git a/internal/apiserver/auth/auth_azure.go b/internal/apiserver/auth/auth_azure.go index 26cf2d7f..ba186799 100644 --- a/internal/apiserver/auth/auth_azure.go +++ b/internal/apiserver/auth/auth_azure.go @@ -7,11 +7,12 @@ import ( "time" "github.com/lestrrat-go/jwx/jwt" + "google.golang.org/protobuf/types/known/timestamppb" + "github.com/nais/device/internal/apiserver/database" "github.com/nais/device/internal/auth" "github.com/nais/device/internal/pb" "github.com/nais/device/internal/random" - "google.golang.org/protobuf/types/known/timestamppb" ) type azureAuth struct { @@ -31,7 +32,7 @@ func NewAuthenticator(azureConfig *auth.Azure, db database.APIServer, store Sess func (s *azureAuth) Login(ctx context.Context, token, serial, platform string) (*pb.Session, error) { parsedToken, err := jwt.ParseString(token, s.Azure.JwtOptions()...) if err != nil { - return nil, fmt.Errorf("parse token: %w", err) + return nil, &ParseTokenError{err} } claims, err := parsedToken.AsMap(ctx) @@ -45,7 +46,7 @@ func (s *azureAuth) Login(ctx context.Context, token, serial, platform string) ( } if !auth.UserInNaisdeviceApprovalGroup(claims) { - return nil, fmt.Errorf("do's and don'ts not accepted, visit: https://naisdevice-approval.external.prod-gcp.nav.cloud.nais.io/ to read and accept") + return nil, ErrTermsNotAccepted } username := claims["preferred_username"].(string) diff --git a/internal/apiserver/auth/errors.go b/internal/apiserver/auth/errors.go new file mode 100644 index 00000000..411e0fa1 --- /dev/null +++ b/internal/apiserver/auth/errors.go @@ -0,0 +1,21 @@ +package auth + +import ( + "errors" + "fmt" +) + +var ErrTermsNotAccepted = errors.New("do's and don'ts not accepted, visit: https://naisdevice-approval.external.prod-gcp.nav.cloud.nais.io/ to read and accept") + +// JWT token parsing errors. +// The token library does not have any standardised error types, +// so we need one here to accurately represent this type of error. +type ParseTokenError struct { + err error +} + +var _ error = &ParseTokenError{} + +func (t ParseTokenError) Error() string { + return fmt.Sprintf("parse token: %s", t.err) +} diff --git a/internal/device-agent/states/connected/connected.go b/internal/device-agent/states/connected/connected.go index b6e7277e..680c1111 100644 --- a/internal/device-agent/states/connected/connected.go +++ b/internal/device-agent/states/connected/connected.go @@ -16,6 +16,7 @@ import ( grpcstatus "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/timestamppb" + "github.com/nais/device/internal/apiserver/auth" "github.com/nais/device/internal/device-agent/config" "github.com/nais/device/internal/device-agent/runtimeconfig" "github.com/nais/device/internal/device-agent/statemachine" @@ -101,6 +102,11 @@ func (c *Connected) Enter(ctx context.Context) statemachine.Event { c.logger.Warnf("Synchronize config: not connected to API server: %v", err) time.Sleep(apiServerRetryInterval * time.Duration(math.Pow(float64(attempt), 3))) continue + case errors.Is(e, auth.ErrTermsNotAccepted): + c.notifier.Errorf("%v", e) + return statemachine.EventDisconnect + case errors.Is(e, &auth.ParseTokenError{}): + fallthrough case errors.Is(e, ErrUnauthenticated): c.notifier.Errorf("Unauthenticated: %v", err) c.rc.SetToken(nil)