Skip to content

Commit b5d94c0

Browse files
Add support for service error headers in auth callout handlers
Signed-off-by: Andrási István <[email protected]>
1 parent 3e60436 commit b5d94c0

File tree

2 files changed

+72
-1
lines changed

2 files changed

+72
-1
lines changed

server/auth_callout.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"unicode"
2424

2525
"github.com/nats-io/jwt/v2"
26+
"github.com/nats-io/nats.go/micro"
2627
"github.com/nats-io/nkeys"
2728
)
2829

@@ -79,7 +80,14 @@ func (s *Server) processClientOrLeafCallout(c *client, opts *Options, proxyRequi
7980

8081
decodeResponse := func(rc *client, rmsg []byte, acc *Account) (*jwt.UserClaims, error) {
8182
account := acc.Name
82-
_, msg := rc.msgParts(rmsg)
83+
hdr, msg := rc.msgParts(rmsg)
84+
if hdr != nil {
85+
code := sliceHeader(micro.ErrorCodeHeader, hdr)
86+
desc := sliceHeader(micro.ErrorHeader, hdr)
87+
if code != nil || desc != nil {
88+
return nil, fmt.Errorf("auth callout service returned an error: %s: %s", code, desc)
89+
}
90+
}
8391

8492
// This signals not authorized.
8593
// Since this is an account subscription will always have "\r\n".

server/auth_callout_test.go

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import (
3131

3232
"github.com/nats-io/jwt/v2"
3333
"github.com/nats-io/nats.go"
34+
"github.com/nats-io/nats.go/micro"
3435
"github.com/nats-io/nkeys"
3536
)
3637

@@ -2492,3 +2493,65 @@ func TestAuthCalloutProxyRequiredInUserNotInAuthJWT(t *testing.T) {
24922493
// Auth callout should have been invoked once.
24932494
require_Equal(t, 1, int(invoked.Load()))
24942495
}
2496+
2497+
func TestAuthCalloutErrorInHeader(t *testing.T) {
2498+
srv, _ := RunServerWithConfig(createConfFile(t, []byte(`
2499+
listen: "127.0.0.1:-1"
2500+
server_name: A
2501+
accounts {
2502+
AUTH: {
2503+
users: [ { user: auth, password: auth } ]
2504+
}
2505+
APP: {
2506+
users: [ { user: user, password: pass } ]
2507+
}
2508+
SYS: {}
2509+
}
2510+
system_account: SYS
2511+
2512+
authorization {
2513+
timeout: 1s
2514+
auth_callout {
2515+
issuer: "`+authCalloutIssuer+`"
2516+
auth_users: [ auth ]
2517+
account: AUTH
2518+
}
2519+
}
2520+
`)))
2521+
t.Cleanup(srv.WaitForShutdown)
2522+
t.Cleanup(srv.Shutdown)
2523+
2524+
authConn, err := nats.Connect(srv.ClientURL(), nats.UserInfo("auth", "auth"))
2525+
require_NoError(t, err)
2526+
t.Cleanup(authConn.Close)
2527+
2528+
authErrSub, err := authConn.SubscribeSync(authErrorAccountEventSubj)
2529+
require_NoError(t, err)
2530+
2531+
_, err = micro.AddService(authConn, micro.Config{
2532+
Name: "AuthCalloutError",
2533+
Version: "0.1.0",
2534+
Description: "Returns an authorization error as service error message headers.",
2535+
Endpoint: &micro.EndpointConfig{
2536+
Subject: AuthCalloutSubject,
2537+
Handler: micro.HandlerFunc(func(req micro.Request) {
2538+
req.Error("500", "custom error message", nil)
2539+
}),
2540+
},
2541+
})
2542+
require_NoError(t, err)
2543+
2544+
_, err = nats.Connect(srv.ClientURL(), nats.UserInfo("user", "pass"))
2545+
require_Error(t, err)
2546+
2547+
msg, err := authErrSub.NextMsg(time.Second)
2548+
require_NoError(t, err)
2549+
2550+
var dmsg DisconnectEventMsg
2551+
err = json.Unmarshal(msg.Data, &dmsg)
2552+
require_NoError(t, err)
2553+
2554+
if !strings.Contains(dmsg.Reason, "500: custom error message") {
2555+
t.Fatalf("reason %q does not contain %q", dmsg.Reason, "500: custom error message")
2556+
}
2557+
}

0 commit comments

Comments
 (0)