Skip to content

Commit

Permalink
Improve cert read (#9)
Browse files Browse the repository at this point in the history
* improved header formatting

* extend
  • Loading branch information
wistefan authored Nov 22, 2022
1 parent 74e2e7c commit 5e70c61
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 32 deletions.
34 changes: 31 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,18 @@ In addition, it expects the certificate and keyfiles under ```/certificates/cert

## Usage

The easiest way to use the tool is docker:
The easiest way to use the tool is docker. Provide a config-file and the corresponding certificate and key. The config file is of form:

```yaml
EU.EORI.NLHAPPYPETS:
certificate: "/happypets/certificate.pem"
key: "/happypets/key.pem"
```
Execute the tool and provide the client and idp id to use from the config:
```shell
docker run -v $(pwd)/example:/certificates -e I_SHARE_CLIENT_ID="EU.EORI.NLHAPPYPETS" -e I_SHARE_IDP_ID="EU.EORI.NLPACKETDEL" quay.io/wi_stefan/ishare-jwt-helper
docker run -v $(pwd)/example:/happypets -v $(pwd)/example/config.yaml:/config.yaml -e I_SHARE_CLIENT_ID="EU.EORI.NLHAPPYPETS" -e I_SHARE_IDP_ID="EU.EORI.NLPACKETDEL" quay.io/wi_stefan/ishare-jwt-helper
```

This will create a token, using the test certificate and key in the [example-folder](./example/) for the client ```EU.EORI.NLHAPPYPETS``` and the intended participant ```EU.EORI.NLPACKETDEL```.
Expand All @@ -29,4 +37,24 @@ Result:
time="2022-06-22T07:01:49Z" level=info msg="CredentialsFolderPath: /certificates"
time="2022-06-22T07:01:49Z" level=info msg="Token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsIng1YyI6WyJNSUlEOXpDQ0F0K2dBd0lCQWdJVVZVckZwOW5wZ1JGN1N5WTRlN05OWDU2aFl5NHdEUVlKS29aSWh2Y05BUUVMQlFBd2dZb3hDekFKQmdOVkJBWVRBa1JGTVE4d0RRWURWUVFJREFaQ1pYSnNhVzR4RHpBTkJnTlZCQWNNQmtKbGNteHBiakVmTUIwR0ExVUVDZ3dXUmtsWFFWSkZJRVp2ZFc1a1lYUnBiMjRnWlM1V0xqRU1NQW9HQTFVRUN3d0RSR1YyTVNvd0tBWUpLb1pJaHZjTkFRa0JGaHRtYVhkaGNtVXRkR1ZqYUMxb1pXeHdRR1pwZDJGeVpTNXZjbWN3SGhjTk1qRXhNVEkwTVRJeE5USXhXaGNOTWpFeE1qSTBNVEl4TlRJeFdqQ0JpakVMTUFrR0ExVUVCaE1DUkVVeER6QU5CZ05WQkFnTUJrSmxjbXhwYmpFUE1BMEdBMVVFQnd3R1FtVnliR2x1TVI4d0hRWURWUVFLREJaR1NWZEJVa1VnUm05MWJtUmhkR2x2YmlCbExsWXVNUXd3Q2dZRFZRUUxEQU5FWlhZeEtqQW9CZ2txaGtpRzl3MEJDUUVXRzJacGQyRnlaUzEwWldOb0xXaGxiSEJBWm1sM1lYSmxMbTl5WnpDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTFg5bWpYNjBjZDRUdVJzTVVCTWVZRVhMVXhsd2lXeEtreForcVNocW5ib1pZaFVlNEFMc1FSRDdvZ0xicjh1WXE4V2prMnFZM2M0WVZHRm4xaEdMZ2c2S2JkV0N6ZnVFbWFKN0pPTy9uQ3hkeGd0MkpvcXpkazhobFU4WUZaRlk0djNCMXZIb2h0TS9kTEU5VnNvTWNndWJPelArVmhkRXY1aExLUFJnR0FuS0IyaGhzN1ZXNERHeUM2QXBMZWRBU1Z3bzhob0NoTUM1cXFwRWhQWXlLdkpBWWJOV1Y5dndpLyswdXJ0cElNdkpocUNjR3ZHTi9TMUtiQlF5THFYakJBRnlSWFptMXBFYWFKTWxKTm00R1c2eUxLZUhhZFBlQndaUnpTR09kZFh4ZzFnaWlXcWtITGtZUUFnV0xXQVcyWEJFZ2VzTHlMa3FTNHNmVnhYb2NNQ0F3RUFBYU5UTUZFd0hRWURWUjBPQkJZRUZFNFF4SkU4WlhCWnM5V2NUcGlZZk1HK2psUjNNQjhHQTFVZEl3UVlNQmFBRkU0UXhKRThaWEJaczlXY1RwaVlmTUcramxSM01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFCbmhkQ0YyTi9SYVFRc0RGMGx6aGlFdkJDa010eWQyVnNOR0ZBcnlXVXl1akpSYlhCQ1hxNkMzdW1jQy9qSHJpd3VIc0JZSkZsSk04VGI4bmVhTTJRRlhRdGxFb0ozVDNuMndVSzArUk1zcUFlb2dRdFFsVVZZMU5ndktlb0pHdXBmQm9qRUxrQU9IWXFNZVhQT0NITjN3cEhZWkYwUWZOMXowYWlxV1FCZ3h1V3A3M2ErQUs3SDg2UEpJOGVleTNib0cwR3lEdG9QVndXNWJSZ0hlbzU5NUVGRHBTZWRJcmQ5ckhWY3F3RUdZRmpoNUZsYmJLQkVqTkRVVjRKbFp1L0pwTWErK0RuUERkOTBFRldaR0tzWnBpM0FMbXlhL2w5RHBFU1NNV1hXZTlaQ1M3cjZ2SGZMQldsNThvcmpYdUtySXRtZ3BZRXZHbVZPKzJ4WkJ1RWc9Il19.eyJhdWQiOiJFVS5FT1JJLk5MUEFDS0VUREVMIiwiZXhwIjoxNjU1ODgxMzM5LCJpYXQiOjE2NTU4ODEzMDksImlzcyI6IkVVLkVPUkkuTkxIQVBQWVBFVFMiLCJqdGkiOiI0MWU5OWE0OC05Mjc4LTRjMjYtOTM3ZC1iYTAxYTQ0OWFiNWUiLCJzdWIiOiJFVS5FT1JJLk5MSEFQUFlQRVRTIn0.ExdTEUp20_5a-M0yu4EQd0dZDhu4u5HCYCQQIb0JwSc6jUrSxgcTu2lTCDA5ct-M9oCBWBSOI2EPR-0DPzzQftZC-7YD_BmAsCnXOzUbR7nKSYrCzM7CwngwhriVLc_pVfzineyG90UsHmPlV1P9n785zEukNzuZLfNyqxtT_z1zfNLl0bg4dc9yz9euLv3zdvOXDsMOI21UPgu3qcGhr0rNStK7Og8AzodHdCZoDyctzKMjiGRIMQzAdmXFIqbx3QAjlQPN0pyG_-3OM8_I685BhCYXvT6ATw-D9HJmWlbyxADccs112S38_LVnOc_DoUBVeYZTFVQAjgwEmIXb9g"
```
Copy the token and use it. Be aware that its only valid for 30s, due to [the specifcation of iShare](https://dev.ishareworks.org/introduction/jwt.html#jwt-payload).
Copy the token and use it. Be aware that its only valid for 30s, due to [the specifcation of iShare](https://dev.ishareworks.org/introduction/jwt.html#jwt-payload).

## Run as server

When the environment variable ```RUN_SERVER``` is set to ```true```, the tool can run as a service. Tokens can be requested with the clientId(has to be configured in the config-file) and the idpId as the the audience of the token. ```/token?clientId=EU.EORI.NLHAPPYPETS&idpId=EU.EORI.NLPACKETDEL```.

```shell
docker run -v $(pwd)/example:/happypets -v $(pwd)/example/config.yaml:/config.yaml -e RUN_SERVER="true" -p 8080:8080 quay.io/wi_stefan/ishare-jwt-helper
```

Get the token:

```shell
curl --location --request GET 'localhost:8080/token?clientId=EU.EORI.NLHAPPYPETS&idpId=EU.EORI.NLPACKETDEL' \
```
Response:
```json
{
"token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsIng1YyI6WyJNSUlEOXpDQ0F0K2dBd0lCQWdJVVZVckZwOW5wZ1JGN1N5WTRlN05OWDU2aFl5NHdEUVlKS29aSWh2Y05BUUVMQlFBd2dZb3hDekFKQmdOVkJBWVRBa1JGTVE4d0RRWURWUVFJREFaQ1pYSnNhVzR4RHpBTkJnTlZCQWNNQmtKbGNteHBiakVmTUIwR0ExVUVDZ3dXUmtsWFFWSkZJRVp2ZFc1a1lYUnBiMjRnWlM1V0xqRU1NQW9HQTFVRUN3d0RSR1YyTVNvd0tBWUpLb1pJaHZjTkFRa0JGaHRtYVhkaGNtVXRkR1ZqYUMxb1pXeHdRR1pwZDJGeVpTNXZjbWN3SGhjTk1qRXhNVEkwTVRJeE5USXhXaGNOTWpFeE1qSTBNVEl4TlRJeFdqQ0JpakVMTUFrR0ExVUVCaE1DUkVVeER6QU5CZ05WQkFnTUJrSmxjbXhwYmpFUE1BMEdBMVVFQnd3R1FtVnliR2x1TVI4d0hRWURWUVFLREJaR1NWZEJVa1VnUm05MWJtUmhkR2x2YmlCbExsWXVNUXd3Q2dZRFZRUUxEQU5FWlhZeEtqQW9CZ2txaGtpRzl3MEJDUUVXRzJacGQyRnlaUzEwWldOb0xXaGxiSEJBWm1sM1lYSmxMbTl5WnpDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTFg5bWpYNjBjZDRUdVJzTVVCTWVZRVhMVXhsd2lXeEtreForcVNocW5ib1pZaFVlNEFMc1FSRDdvZ0xicjh1WXE4V2prMnFZM2M0WVZHRm4xaEdMZ2c2S2JkV0N6ZnVFbWFKN0pPTy9uQ3hkeGd0MkpvcXpkazhobFU4WUZaRlk0djNCMXZIb2h0TS9kTEU5VnNvTWNndWJPelArVmhkRXY1aExLUFJnR0FuS0IyaGhzN1ZXNERHeUM2QXBMZWRBU1Z3bzhob0NoTUM1cXFwRWhQWXlLdkpBWWJOV1Y5dndpLyswdXJ0cElNdkpocUNjR3ZHTi9TMUtiQlF5THFYakJBRnlSWFptMXBFYWFKTWxKTm00R1c2eUxLZUhhZFBlQndaUnpTR09kZFh4ZzFnaWlXcWtITGtZUUFnV0xXQVcyWEJFZ2VzTHlMa3FTNHNmVnhYb2NNQ0F3RUFBYU5UTUZFd0hRWURWUjBPQkJZRUZFNFF4SkU4WlhCWnM5V2NUcGlZZk1HK2psUjNNQjhHQTFVZEl3UVlNQmFBRkU0UXhKRThaWEJaczlXY1RwaVlmTUcramxSM01BOEdBMVVkRXdFQi93UUZNQU1CQWY4d0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFCbmhkQ0YyTi9SYVFRc0RGMGx6aGlFdkJDa010eWQyVnNOR0ZBcnlXVXl1akpSYlhCQ1hxNkMzdW1jQy9qSHJpd3VIc0JZSkZsSk04VGI4bmVhTTJRRlhRdGxFb0ozVDNuMndVSzArUk1zcUFlb2dRdFFsVVZZMU5ndktlb0pHdXBmQm9qRUxrQU9IWXFNZVhQT0NITjN3cEhZWkYwUWZOMXowYWlxV1FCZ3h1V3A3M2ErQUs3SDg2UEpJOGVleTNib0cwR3lEdG9QVndXNWJSZ0hlbzU5NUVGRHBTZWRJcmQ5ckhWY3F3RUdZRmpoNUZsYmJLQkVqTkRVVjRKbFp1L0pwTWErK0RuUERkOTBFRldaR0tzWnBpM0FMbXlhL2w5RHBFU1NNV1hXZTlaQ1M3cjZ2SGZMQldsNThvcmpYdUtySXRtZ3BZRXZHbVZPKzJ4WkJ1RWc9Il19.eyJhdWQiOiJFVS5FT1JJLk5MUEFDS0VUREVMIiwiZXhwIjoxNjY5MTAxMDk5LCJpYXQiOjE2NjkxMDEwNjksImlzcyI6IkVVLkVPUkkuTkxIQVBQWVBFVFMiLCJqdGkiOiJjODAzNWZlMi0xODI4LTQ4YzUtYTU3Yi04OGFiMTdmYTI5OGMiLCJzdWIiOiJFVS5FT1JJLk5MSEFQUFlQRVRTIn0.MbCdMRzoRPZNQrwtwQdFws5E40JWaCglG8ozblXwpUD2Wt3PWAshDEU7gkiTtoTkWSYnpmnfFo4a4fT9DbsWycM-xRR0BKH3pcIPawDVJsag9mk91Q9nGcYXjK54-kUx0nKrko0P7BUhjE5IVrjXtnQxLqGJo-_M7SfFsBxegDRiBu9qB8bTIBENNSMCq_gvcOjeGR0hlRvXlFz4vDxLMHRxadiY9NGfX3duNKKW1dx1vlHx4n0LJ2RwgafMIBLjYmeuSYMb64WoHDMaEff6Yg1H-c_eyGosjeEmLmIBW9ADCC8rMXz0ySq5StdKTIyo92sLrlj5oBREiuGGrHEy7A"
}
```
10 changes: 10 additions & 0 deletions config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package main

type Config struct {
Credentials map[string]Credential
}

type Credential struct {
Certificate string `yaml:"certificate"`
Key string `yaml:"key"`
}
3 changes: 3 additions & 0 deletions example/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
EU.EORI.NLHAPPYPETS:
certificate: "/happypets/certificate.pem"
key: "/happypets/key.pem"
79 changes: 50 additions & 29 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"net/http"
Expand All @@ -16,18 +17,18 @@ import (
"github.com/golang-jwt/jwt"
"github.com/google/uuid"
log "github.com/sirupsen/logrus"
"gopkg.in/yaml.v2"
)

var runServer bool = false

var iShareClientID string
var iShareIdpID string
var defaultKeyPath string = "/certificates/key.pem"
var defaultCertPath string = "/certificates/certificate.pem"
var keyPath string
var certificatePath string
var defaultConfigPath string = "/config.yaml"
var credentials map[string]Credential = map[string]Credential{}
var serverPort int = 8080

var defaultIShareClientID string
var defaultIShareIdpID string

func init() {

serverEnabled, err := strconv.ParseBool(os.Getenv("RUN_SERVER"))
Expand All @@ -41,24 +42,26 @@ func init() {
log.Warnf("No valid server port was provided, run on default %s.", serverPort)
}

iShareClientID = os.Getenv("I_SHARE_CLIENT_ID")
iShareIdpID = os.Getenv("I_SHARE_IDP_ID")
if iShareClientID == "" {
log.Fatalf("No I_SHARE_CLIENT_ID provided")
return
configPath := os.Getenv("CONFIG_PATH")
if configPath == "" {
configPath = defaultConfigPath
}
if iShareIdpID == "" {
log.Fatalf("No I_SHARE_IDP_ID provided")
return
}
keyPath = os.Getenv("KEY_PATH")
certificatePath = os.Getenv("CERT_PATH")
if keyPath == "" {
keyPath = defaultKeyPath

configBytes, err := readFile(configPath)

if err != nil {
log.Fatalf("Was not able to read the config %s.", configPath, err)
}
if certificatePath == "" {
certificatePath = defaultCertPath

err = yaml.Unmarshal(configBytes, credentials)
if err != nil {
log.Fatalf("Was not able to unmarshal config %s.", configPath, err)
}

log.Infof("Config is: %v", credentials)

defaultIShareClientID = os.Getenv("I_SHARE_CLIENT_ID")
defaultIShareIdpID = os.Getenv("I_SHARE_IDP_ID")
}

func main() {
Expand All @@ -72,7 +75,7 @@ func main() {
router.Run(fmt.Sprintf("0.0.0.0:%v", serverPort))
log.Infof("Started router at %v", serverPort)
} else {
token, _ := generateToken()
token, _ := generateToken(defaultIShareClientID, defaultIShareIdpID)
log.Infof("Token: %s", token)
}

Expand All @@ -83,7 +86,18 @@ type Token struct {
}

func token(c *gin.Context) {
token, err := generateToken()
clientId := c.Query("clientId")
idpId := c.Query("idpId")

if clientId == "" {
clientId = defaultIShareClientID
}
if idpId == "" {
idpId = defaultIShareIdpID
}
log.Infof("Creating token for %s - %s", clientId, idpId)

token, err := generateToken(clientId, idpId)

if err != nil {
c.AbortWithError(http.StatusInternalServerError, err)
Expand All @@ -92,7 +106,7 @@ func token(c *gin.Context) {
c.AbortWithStatusJSON(http.StatusOK, Token{token})
}

func generateToken() (token string, err error) {
func generateToken(clientId string, idpId string) (token string, err error) {
randomUuid, err := uuid.NewRandom()

if err != nil {
Expand All @@ -104,14 +118,21 @@ func generateToken() (token string, err error) {
now := time.Now().Unix()
jwtToken := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"jti": randomUuid.String(),
"iss": iShareClientID,
"sub": iShareClientID,
"aud": iShareIdpID,
"iss": clientId,
"sub": clientId,
"aud": idpId,
"iat": now,
"exp": now + 30,
})

key, err := getSigningKey(keyPath)
credential := credentials[clientId]

if credential == (Credential{}) {
log.Errorf("No credentials for %s exist.", clientId)
return token, errors.New("no_such_credentials")
}

key, err := getSigningKey(credential.Key)
if err != nil {
log.Warn("Was not able to read the signing key.")
return
Expand All @@ -121,7 +142,7 @@ func generateToken() (token string, err error) {
return
}

cert, err := getEncodedCertificate(certificatePath)
cert, err := getEncodedCertificate(credential.Certificate)
if err != nil {
log.Warn("Was not able to read the certificate.")
return
Expand Down

0 comments on commit 5e70c61

Please sign in to comment.