| // - |
| // ========================LICENSE_START================================= |
| // O-RAN-SC |
| // %% |
| // Copyright (C) 2022: Nordix Foundation |
| // %% |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| // ========================LICENSE_END=================================== |
| // |
| |
| package main |
| |
| import ( |
| "crypto/tls" |
| "crypto/x509" |
| "encoding/json" |
| "io/ioutil" |
| "net/http" |
| "net/url" |
| "time" |
| |
| "os" |
| |
| log "github.com/sirupsen/logrus" |
| ) |
| |
| type JwtToken struct { |
| Access_token string |
| Expires_in int |
| Token_type string |
| } |
| |
| type Context struct { |
| Running bool |
| Config *Config |
| } |
| |
| func NewContext(config *Config) *Context { |
| return &Context{ |
| Running: true, |
| Config: config, |
| } |
| } |
| |
| // @title Auth token fetcher |
| // @version 1.1.0 |
| |
| // @license.name Apache 2.0 |
| // @license.url http://www.apache.org/licenses/LICENSE-2.0.html |
| |
| func main() { |
| configuration := NewConfig() |
| log.SetLevel(configuration.LogLevel) |
| |
| log.Debug("Using configuration: ", configuration) |
| start(NewContext(configuration)) |
| |
| keepAlive() |
| } |
| |
| func start(context *Context) { |
| log.Debug("Initializing") |
| if err := validateConfiguration(context.Config); err != nil { |
| log.Fatalf("Stopping due to error: %v", err) |
| } |
| |
| cert := loadCertificate(context.Config.CertPath, context.Config.KeyPath) |
| caCerts := loadCaCerts(context.Config.CACertsPath) |
| |
| webClient := CreateHttpClient(cert, caCerts, 10*time.Second) |
| |
| go periodicRefreshIwtToken(webClient, context) |
| } |
| |
| func periodicRefreshIwtToken(webClient *http.Client, context *Context) { |
| for context.Running { |
| jwtToken, err := fetchJwtToken(webClient, context.Config) |
| if check(err) { |
| saveAccessToken(jwtToken, context.Config) |
| } |
| delayTime := calcDelayTime(jwtToken, err, context.Config) |
| log.WithFields(log.Fields{"seconds": delayTime.Seconds()}).Debug("Sleeping") |
| time.Sleep(delayTime) |
| } |
| } |
| |
| func calcDelayTime(token JwtToken, e error, confing *Config) time.Duration { |
| if e != nil { |
| return time.Second * 1 |
| } |
| remains := token.Expires_in - confing.RefreshMarginSeconds |
| if remains < 1 { |
| remains = 1 |
| } |
| return time.Second * time.Duration(remains) |
| } |
| |
| func check(e error) bool { |
| if e != nil { |
| log.Errorf("Failure reason: %v", e) |
| return false |
| } |
| return true |
| } |
| |
| func saveAccessToken(token JwtToken, configuration *Config) { |
| log.WithFields(log.Fields{"file": configuration.AuthTokenOutputFileName}).Debug("Saving access token") |
| data := []byte(token.Access_token) |
| err := os.WriteFile(configuration.AuthTokenOutputFileName, data, 0644) |
| check(err) |
| } |
| |
| func fetchJwtToken(webClient *http.Client, configuration *Config) (JwtToken, error) { |
| log.WithFields(log.Fields{"url": configuration.AuthServiceUrl}).Debug("Fetching token") |
| var jwt JwtToken |
| var err error |
| resp, err := webClient.PostForm(configuration.AuthServiceUrl, |
| url.Values{"client_secret": {configuration.ClientSecret}, "grant_type": {configuration.GrantType}, "client_id": {configuration.ClientId}}) |
| |
| if check(err) { |
| var body []byte |
| defer resp.Body.Close() |
| body, err = ioutil.ReadAll(resp.Body) |
| if check(err) { |
| err = json.Unmarshal([]byte(body), &jwt) |
| } |
| } |
| return jwt, err |
| } |
| |
| func loadCertificate(certPath string, keyPath string) tls.Certificate { |
| log.WithFields(log.Fields{"certPath": certPath, "keyPath": keyPath}).Debug("Loading cert") |
| cert, err := tls.LoadX509KeyPair(certPath, keyPath) |
| if check(err) { |
| return cert |
| } else { |
| log.Fatalf("cannot create x509 keypair from cert file %s and key file %s due to: %v", certPath, keyPath, err) |
| return tls.Certificate{} |
| } |
| } |
| |
| func loadCaCerts(caCertsPath string) *x509.CertPool { |
| var err error |
| if caCertsPath == "" { |
| return nil |
| } |
| caCert, err := ioutil.ReadFile(caCertsPath) |
| check(err) |
| caCertPool := x509.NewCertPool() |
| caCertPool.AppendCertsFromPEM(caCert) |
| return caCertPool |
| } |
| |
| func keepAlive() { |
| channel := make(chan int) |
| <-channel |
| } |