-
Notifications
You must be signed in to change notification settings - Fork 4
/
idp.go
151 lines (124 loc) · 3.88 KB
/
idp.go
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
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
package idp
import (
"bytes"
"context"
"crypto/rsa"
"crypto/x509"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"github.com/Interhyp/metadata-service/internal/acorn/config"
"github.com/Interhyp/metadata-service/internal/acorn/repository"
auzerolog "github.com/StephanHCB/go-autumn-logging-zerolog"
aurestclientprometheus "github.com/StephanHCB/go-autumn-restclient-prometheus"
aurestclientapi "github.com/StephanHCB/go-autumn-restclient/api"
auresthttpclient "github.com/StephanHCB/go-autumn-restclient/implementation/httpclient"
aurestlogging "github.com/StephanHCB/go-autumn-restclient/implementation/requestlogging"
librepo "github.com/StephanHCB/go-backend-service-common/acorns/repository"
"github.com/lestrrat-go/jwx/v2/jwk"
"net/http"
"time"
)
import _ "github.com/go-git/go-git/v5"
type Impl struct {
Configuration librepo.Configuration
CustomConfiguration config.CustomConfiguration
Logging librepo.Logging
IDPClient aurestclientapi.Client
PEMKeySet []string
}
func New(
configuration librepo.Configuration,
customConfig config.CustomConfiguration,
logging librepo.Logging,
) repository.IdentityProvider {
return &Impl{
Configuration: configuration,
CustomConfiguration: customConfig,
Logging: logging,
}
}
func (r *Impl) IsIdentityProvider() bool {
return true
}
func (r *Impl) Setup() error {
ctx := auzerolog.AddLoggerToCtx(context.Background())
if err := r.SetupConnector(ctx); err != nil {
r.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to set up idp connector. BAILING OUT")
return err
}
if err := r.ObtainKeySet(ctx); err != nil {
r.Logging.Logger().Ctx(ctx).Error().WithErr(err).Print("failed to obtain key set from identity provider. BAILING OUT")
return err
}
r.Logging.Logger().Ctx(ctx).Info().Print("successfully set up idp connector")
return nil
}
func (r *Impl) SetupConnector(ctx context.Context) error {
r.Logging.Logger().Ctx(ctx).Info().Print("setting up idp connector")
client, err := auresthttpclient.New(10*time.Second, nil, nil)
if err != nil {
return err
}
aurestclientprometheus.InstrumentHttpClient(client)
logWrapper := aurestlogging.New(client)
r.IDPClient = logWrapper
r.PEMKeySet = make([]string, 0)
return nil
}
func (r *Impl) ObtainKeySet(ctx context.Context) error {
keysetUrl := r.CustomConfiguration.AuthOidcKeySetUrl()
responseMap := make(map[string]interface{})
response := &aurestclientapi.ParsedResponse{
Body: &responseMap,
}
err := r.IDPClient.Perform(ctx, http.MethodGet, keysetUrl, nil, response)
if err != nil {
return err
}
if response.Status != http.StatusOK {
return errors.New("did not receive http 200 from idp")
}
// we have ensured a structured response, so it can't try to misinterpret e.g. blank pages, httpd error messages, ...
keySetBytes, err := json.Marshal(&responseMap)
if err != nil {
return err
}
keySet, err := jwk.Parse(keySetBytes)
if err != nil {
return fmt.Errorf("failed to parse keyset: %v", err)
}
for i := 0; i < keySet.Len(); i++ {
key, ok := keySet.Key(i)
if !ok {
return fmt.Errorf("failed to get key #%d from keyset", i+1)
}
pubKey := &rsa.PublicKey{}
err = key.Raw(pubKey)
if err != nil {
return fmt.Errorf("failed to extract raw rsa public key for key #%d: %s", i+1, err.Error())
}
pubData, err := x509.MarshalPKIXPublicKey(pubKey)
if err != nil {
return fmt.Errorf("failed to marshal key #%d to public key: %s", i+1, err.Error())
}
output := bytes.Buffer{}
err = pem.Encode(&output, &pem.Block{
Type: "PUBLIC KEY",
Bytes: pubData,
})
if err != nil {
return fmt.Errorf("failed to pem encode key #%d: %s", i+1, err.Error())
}
r.PEMKeySet = append(r.PEMKeySet, output.String())
}
return nil
}
func (r *Impl) GetKeySet(ctx context.Context) []string {
return r.PEMKeySet
}
func (r *Impl) VerifyToken(ctx context.Context, token string) error {
// TODO implement
return nil
}