summaryrefslogtreecommitdiff
path: root/client/client.go
blob: 1bfad5f8fc0e61022a5f51477bbd82adabe40584 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package client

import (
	"context"
	"fmt"
	"sync"

	"git.tardisproject.uk/tcmal/vault-plugin-kerberos-secrets/config"
	krbClient "github.com/jcmturner/gokrb5/v8/client"
	krbConfig "github.com/jcmturner/gokrb5/v8/config"
	"github.com/jcmturner/gokrb5/v8/iana/nametype"
	// "github.com/jcmturner/gokrb5/v8/kadmin"
	krbMessages "github.com/jcmturner/gokrb5/v8/messages"
	krbTypes "github.com/jcmturner/gokrb5/v8/types"
)

type client struct {
	*sync.Mutex

	kCfg    *krbConfig.Config
	kClient *krbClient.Client
}

func ClientFromConfig(config *config.Config) (client, error) {
	kCfg := krbConfig.New()
	kCfg.Realms = []krbConfig.Realm{
		{
			Realm:         config.Realm,
			DefaultDomain: config.Realm,
			KDC:           config.KDC,
			KPasswdServer: config.KPasswdServer,
			AdminServer:   []string{},
			MasterKDC:     config.KDC,
		},
	}

	kClient := krbClient.NewWithPassword(config.Username, config.Realm, config.Password, kCfg)

	return client{
		&sync.Mutex{},
		kCfg,
		kClient,
	}, nil
}

func (c client) SetPassword(ctx context.Context, username string, password string) error {
	c.Lock()
	defer c.Unlock()

	if err := c.kClient.AffirmLogin(); err != nil {
		return fmt.Errorf("error logging in as admin principal: %e", err)
	}

	// Get a ticket for using kadmin/admin
	cl := c.kClient
	ASReq, err := krbMessages.NewASReqForChgPasswd(cl.Credentials.Domain(), cl.Config, cl.Credentials.CName())
	if err != nil {
		return fmt.Errorf("error creating ticket request for kadmin: %s", err)
	}
	ASRep, err := cl.ASExchange(cl.Credentials.Domain(), ASReq, 0)
	if err != nil {
		return fmt.Errorf("error exchanging request for kadmin ticket: %s", err)
	}

	// Construct the change passwd msg
	msg, key, err := ChangePasswdMsg(
		krbTypes.NewPrincipalName(nametype.KRB_NT_PRINCIPAL, username),
		cl.Credentials.CName(),
		cl.Credentials.Domain(),
		password,
		ASRep.Ticket,
		ASRep.DecryptedEncPart.Key,
	)

	if err != nil {
		return fmt.Errorf("error creating change passwd msg: %s", err)
	}

	// Send it to kpasswd
	r, err := sendToKAdmin(cl, msg)
	if err != nil {
		return fmt.Errorf("error communicating with kpasswd: %s", err)
	}

	// Decrypt the result
	if r.ResultCode != 0 {
		return fmt.Errorf("error response from kadmin: code: %d; result: %s; krberror: %v", r.ResultCode, r.Result, r.KRBError)
	}

	err = r.Decrypt(key)
	if err != nil {
		return fmt.Errorf("error decrypting result: %s", err)
	}

	return nil
}