Skip to content

Commit 9b24d56

Browse files
Support client authentication (#24)
* Support basic authentication in Client * Implement server basic auth logic * Update websocket package documentation * Add custom HttpConnectionError * Add tests for basic auth * Support TLS config on websocket server * Add tests for TLS certificates with websockets * Pass CA certificate path to 1.6 central system in docker-compose.tls * Fix nil httpServer in websocket server
1 parent 716a28a commit 9b24d56

File tree

6 files changed

+541
-88
lines changed

6 files changed

+541
-88
lines changed

example/1.6/cs/central_system_sim.go

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package main
22

33
import (
4+
"crypto/tls"
5+
"crypto/x509"
46
ocpp16 "github.com/lorenzodonini/ocpp-go/ocpp1.6"
57
"github.com/lorenzodonini/ocpp-go/ocpp1.6/core"
68
"github.com/lorenzodonini/ocpp-go/ocpp1.6/firmware"
@@ -10,6 +12,7 @@ import (
1012
"github.com/lorenzodonini/ocpp-go/ocpp1.6/types"
1113
"github.com/lorenzodonini/ocpp-go/ws"
1214
log "github.com/sirupsen/logrus"
15+
"io/ioutil"
1316
"os"
1417
"strconv"
1518
"time"
@@ -20,6 +23,7 @@ const (
2023
defaultHeartbeatInterval = 600
2124
envVarServerPort = "SERVER_LISTEN_PORT"
2225
envVarTls = "TLS_ENABLED"
26+
envVarCaCertificate = "CA_CERTIFICATE_PATH"
2327
envVarServerCertificate = "SERVER_CERTIFICATE_PATH"
2428
envVarServerCertificateKey = "SERVER_CERTIFICATE_KEY_PATH"
2529
)
@@ -31,6 +35,27 @@ func setupCentralSystem() ocpp16.CentralSystem {
3135
}
3236

3337
func setupTlsCentralSystem() ocpp16.CentralSystem {
38+
var certPool *x509.CertPool
39+
// Load CA certificates
40+
caCertificate, ok := os.LookupEnv(envVarCaCertificate)
41+
if !ok {
42+
log.Infof("no %v found, using system CA pool", envVarCaCertificate)
43+
systemPool, err := x509.SystemCertPool()
44+
if err != nil {
45+
log.Fatalf("couldn't get system CA pool: %v", err)
46+
}
47+
certPool = systemPool
48+
} else {
49+
certPool = x509.NewCertPool()
50+
data, err := ioutil.ReadFile(caCertificate)
51+
if err != nil {
52+
log.Fatalf("couldn't read CA certificate from %v: %v", caCertificate, err)
53+
}
54+
ok = certPool.AppendCertsFromPEM(data)
55+
if !ok {
56+
log.Fatalf("couldn't read CA certificate from %v", caCertificate)
57+
}
58+
}
3459
certificate, ok := os.LookupEnv(envVarServerCertificate)
3560
if !ok {
3661
log.Fatalf("no required %v found", envVarServerCertificate)
@@ -39,7 +64,10 @@ func setupTlsCentralSystem() ocpp16.CentralSystem {
3964
if !ok {
4065
log.Fatalf("no required %v found", envVarServerCertificateKey)
4166
}
42-
server := ws.NewTLSServer(certificate, key)
67+
server := ws.NewTLSServer(certificate, key, &tls.Config{
68+
ClientAuth: tls.RequireAndVerifyClientCert,
69+
ClientCAs: certPool,
70+
})
4371
return ocpp16.NewCentralSystem(nil, server)
4472
}
4573

@@ -57,7 +85,7 @@ func exampleRoutine(chargePointID string, handler *CentralSystemHandler) {
5785
logDefault(chargePointID, confirmation.GetFeatureName()).Warn(err)
5886
} else if confirmation.Status == reservation.ReservationStatusAccepted {
5987
logDefault(chargePointID, confirmation.GetFeatureName()).Infof("connector %v reserved for client %v until %v (reservation ID %d)", connectorID, clientIdTag, expiryDate.FormatTimestamp(), reservationID)
60-
} else {
88+
} else {
6189
logDefault(chargePointID, confirmation.GetFeatureName()).Infof("couldn't reserve connector %v: %v", connectorID, confirmation.Status)
6290
}
6391
}
@@ -74,7 +102,7 @@ func exampleRoutine(chargePointID string, handler *CentralSystemHandler) {
74102
logDefault(chargePointID, confirmation.GetFeatureName()).Warn(err)
75103
} else if confirmation.Status == reservation.CancelReservationStatusAccepted {
76104
logDefault(chargePointID, confirmation.GetFeatureName()).Infof("reservation %v canceled successfully", reservationID)
77-
} else {
105+
} else {
78106
logDefault(chargePointID, confirmation.GetFeatureName()).Infof("couldn't cancel reservation %v", reservationID)
79107
}
80108
}

example/1.6/cs/handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,4 +181,4 @@ func (handler *CentralSystemHandler) OnFirmwareStatusNotification(chargePointId
181181

182182
func logDefault(chargePointId string, feature string) *log.Entry {
183183
return log.WithFields(log.Fields{"client": chargePointId, "message": feature})
184-
}
184+
}

example/1.6/docker-compose.tls.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ services:
1212
environment:
1313
- SERVER_LISTEN_PORT=443
1414
- TLS_ENABLED=true
15+
- CA_CERTIFICATE_PATH=/usr/local/share/certs/ca.crt
1516
- SERVER_CERTIFICATE_PATH=/usr/local/share/certs/central-system.crt
1617
- SERVER_CERTIFICATE_KEY_PATH=/usr/local/share/certs/central-system.key
1718
ports:

ocpp2.0_test/ocpp2_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -568,9 +568,9 @@ type expectedChargingStationOptions struct {
568568
forwardWrittenMessage bool
569569
}
570570

571-
func setupDefaultCSMSHandlers(suite *OcppV2TestSuite, options expectedCSMSOptions, handlers... interface{}) {
571+
func setupDefaultCSMSHandlers(suite *OcppV2TestSuite, options expectedCSMSOptions, handlers ...interface{}) {
572572
t := suite.T()
573-
for _,h := range handlers {
573+
for _, h := range handlers {
574574
switch h.(type) {
575575
case MockCSMSAuthorizationHandler:
576576
suite.csms.SetAuthorizationHandler(h.(MockCSMSAuthorizationHandler))
@@ -627,7 +627,7 @@ func setupDefaultCSMSHandlers(suite *OcppV2TestSuite, options expectedCSMSOption
627627
})
628628
}
629629

630-
func setupDefaultChargingStationHandlers(suite *OcppV2TestSuite, options expectedChargingStationOptions, handlers... interface{}) {
630+
func setupDefaultChargingStationHandlers(suite *OcppV2TestSuite, options expectedChargingStationOptions, handlers ...interface{}) {
631631
t := suite.T()
632632
for _, h := range handlers {
633633
switch h.(type) {
@@ -692,7 +692,7 @@ func assertDateTimeEquality(t *testing.T, expected *types.DateTime, actual *type
692692
assert.Equal(t, expected.FormatTimestamp(), actual.FormatTimestamp())
693693
}
694694

695-
func testUnsupportedRequestFromChargingStation(suite *OcppV2TestSuite, request ocpp.Request, requestJson string, messageId string, handlers... interface{}) {
695+
func testUnsupportedRequestFromChargingStation(suite *OcppV2TestSuite, request ocpp.Request, requestJson string, messageId string, handlers ...interface{}) {
696696
t := suite.T()
697697
wsId := "test_id"
698698
wsUrl := "someUrl"
@@ -729,7 +729,7 @@ func testUnsupportedRequestFromChargingStation(suite *OcppV2TestSuite, request o
729729
assert.True(t, result)
730730
}
731731

732-
func testUnsupportedRequestFromCentralSystem(suite *OcppV2TestSuite, request ocpp.Request, requestJson string, messageId string, handlers... interface{}) {
732+
func testUnsupportedRequestFromCentralSystem(suite *OcppV2TestSuite, request ocpp.Request, requestJson string, messageId string, handlers ...interface{}) {
733733
t := suite.T()
734734
wsId := "test_id"
735735
wsUrl := "someUrl"

0 commit comments

Comments
 (0)