Skip to content

Commit 4a1889c

Browse files
authored
feat: oidc client create command (#672)
* feat: add oidc client create command * refactor: use own utility for creating random strings (more flexible than stdlib) * feat: validate client name to avoid config errors * refactor: limit to only alphanumeric characters and hyphens * refactor: remove the need of the logger in the create oidc client cmd
1 parent 5acac0e commit 4a1889c

9 files changed

Lines changed: 77 additions & 11 deletions

File tree

cmd/tinyauth/create_oidc_client.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package main
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"regexp"
7+
8+
"github.com/google/uuid"
9+
"github.com/steveiliop56/tinyauth/internal/utils"
10+
"github.com/traefik/paerser/cli"
11+
)
12+
13+
func createOidcClientCmd() *cli.Command {
14+
return &cli.Command{
15+
Name: "create",
16+
Description: "Create a new OIDC Client",
17+
Configuration: nil,
18+
Resources: nil,
19+
AllowArg: true,
20+
Run: func(args []string) error {
21+
if len(args) == 0 {
22+
return errors.New("client name is required. use tinyauth oidc create <name>")
23+
}
24+
25+
clientName := args[0]
26+
27+
match, err := regexp.MatchString("^[a-zA-Z0-9-]*$", clientName)
28+
29+
if !match || err != nil {
30+
return errors.New("client name can only contain alphanumeric characters and hyphens")
31+
}
32+
33+
uuid := uuid.New()
34+
clientId := uuid.String()
35+
clientSecret := "ta-" + utils.GenerateString(61)
36+
37+
fmt.Printf("Client Name: %s\n", clientName)
38+
fmt.Printf("Client ID: %s\n", clientId)
39+
fmt.Printf("Client Secret: %s\n", clientSecret)
40+
return nil
41+
},
42+
}
43+
}

cmd/tinyauth/tinyauth.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ func main() {
2323

2424
cmdTinyauth := &cli.Command{
2525
Name: "tinyauth",
26-
Description: "The simplest way to protect your apps with a login screen.",
26+
Description: "The simplest way to protect your apps with a login screen",
2727
Configuration: tConfig,
2828
Resources: loaders,
2929
Run: func(_ []string) error {
@@ -33,12 +33,17 @@ func main() {
3333

3434
cmdUser := &cli.Command{
3535
Name: "user",
36-
Description: "Utilities for creating and verifying Tinyauth users.",
36+
Description: "Manage Tinyauth users",
3737
}
3838

3939
cmdTotp := &cli.Command{
4040
Name: "totp",
41-
Description: "Utilities for creating Tinyauth TOTP users.",
41+
Description: "Manage Tinyauth TOTP users",
42+
}
43+
44+
cmdOidc := &cli.Command{
45+
Name: "oidc",
46+
Description: "Manage Tinyauth OIDC clients",
4247
}
4348

4449
err := cmdTinyauth.AddCommand(versionCmd())
@@ -71,6 +76,12 @@ func main() {
7176
log.Fatal().Err(err).Msg("Failed to add create command")
7277
}
7378

79+
err = cmdOidc.AddCommand(createOidcClientCmd())
80+
81+
if err != nil {
82+
log.Fatal().Err(err).Msg("Failed to add create command")
83+
}
84+
7485
err = cmdTinyauth.AddCommand(cmdUser)
7586

7687
if err != nil {
@@ -83,6 +94,12 @@ func main() {
8394
log.Fatal().Err(err).Msg("Failed to add totp command")
8495
}
8596

97+
err = cmdTinyauth.AddCommand(cmdOidc)
98+
99+
if err != nil {
100+
log.Fatal().Err(err).Msg("Failed to add oidc command")
101+
}
102+
86103
err = cli.Execute(cmdTinyauth)
87104

88105
if err != nil {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func verifyUserCmd() *cli.Command {
4040

4141
return &cli.Command{
4242
Name: "verify",
43-
Description: "Verify a user is set up correctly.",
43+
Description: "Verify a user is set up correctly",
4444
Configuration: tCfg,
4545
Resources: loaders,
4646
Run: func(_ []string) error {

cmd/tinyauth/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
func versionCmd() *cli.Command {
1212
return &cli.Command{
1313
Name: "version",
14-
Description: "Print the version number of Tinyauth.",
14+
Description: "Print the version number of Tinyauth",
1515
Configuration: nil,
1616
Resources: nil,
1717
Run: func(_ []string) error {

internal/controller/oidc_controller.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package controller
22

33
import (
4-
"crypto/rand"
54
"errors"
65
"fmt"
76
"net/http"
@@ -145,7 +144,7 @@ func (controller *OIDCController) Authorize(c *gin.Context) {
145144

146145
// WARNING: Since Tinyauth is stateless, we cannot have a sub that never changes. We will just create a uuid out of the username and client name which remains stable, but if username or client name changes then sub changes too.
147146
sub := utils.GenerateUUID(fmt.Sprintf("%s:%s", userContext.Username, client.ID))
148-
code := rand.Text()
147+
code := utils.GenerateString(32)
149148

150149
// Before storing the code, delete old session
151150
err = controller.oidc.DeleteOldSession(c, sub)

internal/service/oidc_service.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,8 @@ func (service *OIDCService) GenerateAccessToken(c *gin.Context, client config.OI
403403
return TokenResponse{}, err
404404
}
405405

406-
accessToken := rand.Text()
407-
refreshToken := rand.Text()
406+
accessToken := utils.GenerateString(32)
407+
refreshToken := utils.GenerateString(32)
408408

409409
tokenExpiresAt := time.Now().Add(time.Duration(service.config.SessionExpiry) * time.Second).Unix()
410410

@@ -464,8 +464,8 @@ func (service *OIDCService) RefreshAccessToken(c *gin.Context, refreshToken stri
464464
return TokenResponse{}, err
465465
}
466466

467-
accessToken := rand.Text()
468-
newRefreshToken := rand.Text()
467+
accessToken := utils.GenerateString(32)
468+
newRefreshToken := utils.GenerateString(32)
469469

470470
tokenExpiresAt := time.Now().Add(time.Duration(service.config.SessionExpiry) * time.Second).Unix()
471471
refrshTokenExpiresAt := time.Now().Add(time.Duration(service.config.SessionExpiry*2) * time.Second).Unix()

internal/utils/security_utils.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package utils
22

33
import (
4+
"crypto/rand"
45
"encoding/base64"
56
"errors"
67
"net"
@@ -105,3 +106,9 @@ func GenerateUUID(str string) string {
105106
uuid := uuid.NewSHA1(uuid.NameSpaceURL, []byte(str))
106107
return uuid.String()
107108
}
109+
110+
func GenerateString(length int) string {
111+
src := make([]byte, length)
112+
rand.Read(src)
113+
return base64.RawURLEncoding.EncodeToString(src)[:length]
114+
}

0 commit comments

Comments
 (0)