Skip to content

Commit e8ebfd7

Browse files
authored
fix: implement openvpn.client-config.token-claim (#681)
1 parent 24b3bc7 commit e8ebfd7

File tree

5 files changed

+54
-10
lines changed

5 files changed

+54
-10
lines changed

internal/oauth2/handler.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import (
1919
)
2020

2121
type openvpnManagementClient interface {
22-
AcceptClient(ctx context.Context, logger *slog.Logger, client state.ClientIdentifier, reAuth bool, username string)
22+
AcceptClient(ctx context.Context, logger *slog.Logger, client state.ClientIdentifier, reAuth bool, username string, clientConfigName string)
2323
DenyClient(ctx context.Context, logger *slog.Logger, client state.ClientIdentifier, reason string)
2424
}
2525

@@ -197,7 +197,17 @@ func (c Client) postCodeExchangeHandler(
197197
username = session.Client.CommonName
198198
}
199199

200-
c.openvpn.AcceptClient(ctx, logger, session.Client, false, username)
200+
clientConfigName := username
201+
202+
if clientConfigClaim := c.conf.OpenVPN.ClientConfig.TokenClaim; clientConfigClaim != "" && tokens.IDTokenClaims != nil {
203+
if claimValue, ok := tokens.IDTokenClaims.Claims[clientConfigClaim]; ok {
204+
if clientConfigTokenValue, ok := claimValue.(string); ok && clientConfigName != "" {
205+
clientConfigName = clientConfigTokenValue
206+
}
207+
}
208+
}
209+
210+
c.openvpn.AcceptClient(ctx, logger, session.Client, false, username, clientConfigName)
201211
c.postCodeExchangeHandlerStoreRefreshToken(ctx, logger, session, clientID, tokens)
202212
c.writeHTTPSuccess(ctx, w, logger)
203213
}

internal/oauth2/handler_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,40 @@ func TestHandler(t *testing.T) {
365365
true,
366366
true,
367367
},
368+
{
369+
"with client config and custom claim",
370+
func() config.Config {
371+
conf := config.Defaults
372+
conf.HTTP.Secret = testutils.Secret
373+
conf.HTTP.Check.IPAddr = true
374+
conf.HTTP.EnableProxyHeaders = true
375+
conf.OAuth2.Provider = generic.Name
376+
conf.OAuth2.Endpoints = config.OAuth2Endpoints{}
377+
conf.OAuth2.Scopes = []string{oauth2types.ScopeOpenID, oauth2types.ScopeProfile}
378+
conf.OAuth2.Validate.Groups = make([]string, 0)
379+
conf.OAuth2.Validate.Roles = make([]string, 0)
380+
conf.OAuth2.Validate.Issuer = true
381+
conf.OAuth2.Validate.IPAddr = false
382+
conf.OpenVPN.Bypass.CommonNames = make(types.RegexpSlice, 0)
383+
conf.OpenVPN.AuthTokenUser = true
384+
conf.OpenVPN.ClientConfig.Enabled = true
385+
conf.OpenVPN.ClientConfig.TokenClaim = "sub"
386+
conf.OpenVPN.ClientConfig.Path = types.FS{
387+
FS: fstest.MapFS{
388+
"id1.conf": &fstest.MapFile{
389+
Data: []byte("push \"ping 60\"\npush \"ping-restart 180\"\r\npush \"ping-timer-rem\" 0\r\n"),
390+
},
391+
},
392+
}
393+
394+
return conf
395+
}(),
396+
state.New(state.ClientIdentifier{CID: 0, KID: 1, CommonName: "name"}, "127.0.0.2", "12345", ""),
397+
false,
398+
"127.0.0.2, 8.8.8.8",
399+
true,
400+
true,
401+
},
368402
{
369403
"with client config not found",
370404
func() config.Config {

internal/openvpn/callbacks.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313

1414
// AcceptClient accepts an OpenVPN client connection.
1515
// It reads the client configuration from the CCD path if enabled.
16-
func (c *Client) AcceptClient(ctx context.Context, logger *slog.Logger, client state.ClientIdentifier, reAuth bool, username string) {
16+
func (c *Client) AcceptClient(ctx context.Context, logger *slog.Logger, client state.ClientIdentifier, reAuth bool, username, clientConfigName string) {
1717
if reAuth {
1818
logger.LogAttrs(ctx, slog.LevelInfo, "client re-authentication")
1919

@@ -26,22 +26,22 @@ func (c *Client) AcceptClient(ctx context.Context, logger *slog.Logger, client s
2626
return
2727
}
2828

29-
c.acceptClientAuth(ctx, logger, client, username)
29+
c.acceptClientAuth(ctx, logger, client, username, clientConfigName)
3030
}
3131

3232
//nolint:cyclop
33-
func (c *Client) acceptClientAuth(ctx context.Context, logger *slog.Logger, client state.ClientIdentifier, username string) {
33+
func (c *Client) acceptClientAuth(ctx context.Context, logger *slog.Logger, client state.ClientIdentifier, username, clientConfigName string) {
3434
var (
3535
err error
3636
tokenUsername string
3737
)
3838

3939
logger.LogAttrs(ctx, slog.LevelInfo, "client authentication")
4040

41-
clientConfig, err := c.readClientConfig(username)
41+
clientConfig, err := c.readClientConfig(clientConfigName)
4242
if err != nil {
4343
logger.LogAttrs(ctx, slog.LevelDebug, "failed to read client config",
44-
slog.String("username", username),
44+
slog.String("config", clientConfigName),
4545
slog.Any("error", err),
4646
)
4747
}

internal/openvpn/client.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func (c *Client) handleClientAuthentication(ctx context.Context, logger *slog.Lo
5858
// Check if the client is allowed to bypass authentication. If so, accept the client.
5959
if c.checkAuthBypass(client) {
6060
logger.LogAttrs(ctx, slog.LevelInfo, "client bypass authentication")
61-
c.AcceptClient(ctx, logger, state.ClientIdentifier{CID: client.CID, KID: client.KID}, true, client.CommonName)
61+
c.AcceptClient(ctx, logger, state.ClientIdentifier{CID: client.CID, KID: client.KID}, true, client.CommonName, "")
6262

6363
return
6464
}
@@ -83,7 +83,7 @@ func (c *Client) handleClientAuthentication(ctx context.Context, logger *slog.Lo
8383

8484
return
8585
} else if ok {
86-
c.AcceptClient(ctx, logger, state.ClientIdentifier{CID: client.CID, KID: client.KID}, true, client.CommonName)
86+
c.AcceptClient(ctx, logger, state.ClientIdentifier{CID: client.CID, KID: client.KID}, true, client.CommonName, "")
8787

8888
return
8989
}

internal/utils/testutils/openvpn.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func NewFakeOpenVPNClient() FakeOpenVPNClient {
1717
}
1818

1919
// AcceptClient is a no-op implementation of the real method.
20-
func (FakeOpenVPNClient) AcceptClient(_ context.Context, _ *slog.Logger, _ state.ClientIdentifier, _ bool, _ string) {
20+
func (FakeOpenVPNClient) AcceptClient(_ context.Context, _ *slog.Logger, _ state.ClientIdentifier, _ bool, _, _ string) {
2121
}
2222

2323
// DenyClient is a no-op implementation of the real method.

0 commit comments

Comments
 (0)