blob: 18003ba60f1efefec2d7b2909b8c27826d40dd58 [file] [log] [blame]
PatrikBuhr07b21182022-03-10 16:07:56 +01001// -
2// ========================LICENSE_START=================================
3// O-RAN-SC
4// %%
5// Copyright (C) 2022: Nordix Foundation
6// %%
7// Licensed under the Apache License, Version 2.0 (the "License");
8// you may not use this file except in compliance with the License.
9// You may obtain a copy of the License at
10//
11// http://www.apache.org/licenses/LICENSE-2.0
12//
13// Unless required by applicable law or agreed to in writing, software
14// distributed under the License is distributed on an "AS IS" BASIS,
15// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16// See the License for the specific language governing permissions and
17// limitations under the License.
18// ========================LICENSE_END===================================
19//
20
21package main
22
23import (
24 "crypto/tls"
PatrikBuhrf4ad7492022-03-23 08:15:21 +010025 "crypto/x509"
PatrikBuhr07b21182022-03-10 16:07:56 +010026 "encoding/json"
PatrikBuhr07b21182022-03-10 16:07:56 +010027 "io/ioutil"
28 "net/http"
29 "net/url"
30 "time"
31
32 "os"
33
34 log "github.com/sirupsen/logrus"
35)
36
37type JwtToken struct {
38 Access_token string
39 Expires_in int
40 Token_type string
41}
42
43type Context struct {
44 Running bool
45 Config *Config
46}
47
48func NewContext(config *Config) *Context {
49 return &Context{
50 Running: true,
51 Config: config,
52 }
53}
54
55// @title Auth token fetcher
elinuxhenrik7dc96e92022-08-18 10:02:03 +020056// @version 1.0.0
PatrikBuhr07b21182022-03-10 16:07:56 +010057
58// @license.name Apache 2.0
59// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
60
61func main() {
62 configuration := NewConfig()
63 log.SetLevel(configuration.LogLevel)
64
65 log.Debug("Using configuration: ", configuration)
66 start(NewContext(configuration))
67
68 keepAlive()
69}
70
71func start(context *Context) {
72 log.Debug("Initializing")
73 if err := validateConfiguration(context.Config); err != nil {
74 log.Fatalf("Stopping due to error: %v", err)
75 }
76
PatrikBuhrf4ad7492022-03-23 08:15:21 +010077 cert := loadCertificate(context.Config.CertPath, context.Config.KeyPath)
78 caCerts := loadCaCerts(context.Config.CACertsPath)
PatrikBuhr07b21182022-03-10 16:07:56 +010079
PatrikBuhrf4ad7492022-03-23 08:15:21 +010080 webClient := CreateHttpClient(cert, caCerts, 10*time.Second)
PatrikBuhr07b21182022-03-10 16:07:56 +010081
82 go periodicRefreshIwtToken(webClient, context)
83}
84
85func periodicRefreshIwtToken(webClient *http.Client, context *Context) {
86 for context.Running {
87 jwtToken, err := fetchJwtToken(webClient, context.Config)
88 if check(err) {
89 saveAccessToken(jwtToken, context.Config)
90 }
91 delayTime := calcDelayTime(jwtToken, err, context.Config)
92 log.WithFields(log.Fields{"seconds": delayTime.Seconds()}).Debug("Sleeping")
93 time.Sleep(delayTime)
94 }
95}
96
97func calcDelayTime(token JwtToken, e error, confing *Config) time.Duration {
98 if e != nil {
99 return time.Second * 1
100 }
101 remains := token.Expires_in - confing.RefreshMarginSeconds
102 if remains < 1 {
103 remains = 1
104 }
105 return time.Second * time.Duration(remains)
106}
107
108func check(e error) bool {
109 if e != nil {
110 log.Errorf("Failure reason: %v", e)
111 return false
112 }
113 return true
114}
115
116func saveAccessToken(token JwtToken, configuration *Config) {
117 log.WithFields(log.Fields{"file": configuration.AuthTokenOutputFileName}).Debug("Saving access token")
118 data := []byte(token.Access_token)
119 err := os.WriteFile(configuration.AuthTokenOutputFileName, data, 0644)
120 check(err)
121}
122
123func fetchJwtToken(webClient *http.Client, configuration *Config) (JwtToken, error) {
124 log.WithFields(log.Fields{"url": configuration.AuthServiceUrl}).Debug("Fetching token")
125 var jwt JwtToken
126 var err error
127 resp, err := webClient.PostForm(configuration.AuthServiceUrl,
128 url.Values{"client_secret": {configuration.ClientSecret}, "grant_type": {configuration.GrantType}, "client_id": {configuration.ClientId}})
129
130 if check(err) {
131 var body []byte
132 defer resp.Body.Close()
133 body, err = ioutil.ReadAll(resp.Body)
134 if check(err) {
135 err = json.Unmarshal([]byte(body), &jwt)
136 }
137 }
138 return jwt, err
139}
140
PatrikBuhrf4ad7492022-03-23 08:15:21 +0100141func loadCertificate(certPath string, keyPath string) tls.Certificate {
PatrikBuhr07b21182022-03-10 16:07:56 +0100142 log.WithFields(log.Fields{"certPath": certPath, "keyPath": keyPath}).Debug("Loading cert")
PatrikBuhrf4ad7492022-03-23 08:15:21 +0100143 cert, err := tls.LoadX509KeyPair(certPath, keyPath)
144 if check(err) {
145 return cert
PatrikBuhr07b21182022-03-10 16:07:56 +0100146 } else {
PatrikBuhrf4ad7492022-03-23 08:15:21 +0100147 log.Fatalf("cannot create x509 keypair from cert file %s and key file %s due to: %v", certPath, keyPath, err)
148 return tls.Certificate{}
PatrikBuhr07b21182022-03-10 16:07:56 +0100149 }
150}
151
PatrikBuhrf4ad7492022-03-23 08:15:21 +0100152func loadCaCerts(caCertsPath string) *x509.CertPool {
153 var err error
154 if caCertsPath == "" {
155 return nil
156 }
157 caCert, err := ioutil.ReadFile(caCertsPath)
158 check(err)
159 caCertPool := x509.NewCertPool()
160 caCertPool.AppendCertsFromPEM(caCert)
161 return caCertPool
162}
163
PatrikBuhr07b21182022-03-10 16:07:56 +0100164func keepAlive() {
165 channel := make(chan int)
166 <-channel
167}