Compare commits

...

20 Commits

Author SHA1 Message Date
DiddiZ
dcb7b79fd7 Fixed admin password being boolean. 2017-02-02 22:28:18 +01:00
DiddiZ
46edc84421 Added BasicAuth to admin handlers. (SommerEngineering/KPIManager#8) 2017-02-02 22:15:48 +01:00
DiddiZ
4a01aaf9bd Added Templates.AddTemplate 2017-01-19 11:36:10 +01:00
Thorsten Sommer
50f4836e44 Fixed TLS for ICCC
Added the hostname of the public server in order to send ICCC messages over TLS and HTTP/2
2016-03-16 12:26:48 +01:00
Thorsten Sommer
4ef6e64a45 Added TLS and HTTP/2 support
In order to use TLS and HTTP/2, add the necessary certificate and the key to the staticFiles.zip file and configure Ocean to enable it.
2016-03-16 10:11:05 +01:00
Thorsten Sommer
4fcb0d9ca2 Bugfix: UUID
The external UUID library changed the text formatting of the UUIDs. Thus, Ocean produces a too short UUID!
2016-02-13 23:17:36 +01:00
Thorsten Sommer
c7b2050cfe Merge pull request #51 from SommerEngineering/v2.0.6
2.0.7
2016-01-08 08:56:40 +00:00
Thorsten Sommer
27e3eef7fc Merge pull request #50 from SommerEngineering/master
2.0.7
2016-01-08 08:55:10 +00:00
Thorsten Sommer
b2cf41a088 Version 2.0.7 2016-01-05 20:50:43 +01:00
Thorsten Sommer
a72d45d27c Fixed the ICCC::Kind enum 2015-07-20 19:54:37 +02:00
Thorsten Sommer
0c80f4bdcc Fixed the ICCC::Kind enum 2015-07-20 19:53:46 +02:00
Thorsten Sommer
47fc86f490 README 2015-07-16 20:35:43 +02:00
Thorsten Sommer
e316ccbf95 README 2015-07-16 20:34:57 +02:00
Thorsten Sommer
4dfda5a807 Fixed ping command and one log event 2015-07-16 18:51:59 +02:00
Thorsten Sommer
744a817150 Adjusted the ICCC driver specification 2015-07-16 13:11:40 +02:00
Thorsten Sommer
4ebaaebaa7 Fixed ICCC driver specification 2015-07-16 10:05:29 +02:00
Thorsten Sommer
210373280f Changed the ICCC driver specification 2015-07-16 08:45:22 +02:00
Thorsten Sommer
ca8a960896 Extend the ICCC driver specification 2015-07-15 21:12:48 +02:00
Thorsten Sommer
d071609988 Bugfix: The start-up message's values are wrong 2015-07-15 19:25:45 +02:00
Thorsten Sommer
c1748edd8d Bugfix for the LogImpact class 2015-07-15 14:31:45 +02:00
23 changed files with 276 additions and 107 deletions

View File

@ -14,13 +14,21 @@ func checkConfiguration() {
CheckSingleConfigurationPresentsAndAddIfMissing(`DefaultLanguageCode`, `en-GB`) CheckSingleConfigurationPresentsAndAddIfMissing(`DefaultLanguageCode`, `en-GB`)
CheckSingleConfigurationPresentsAndAddIfMissing(`AdminWebServerBinding`, `127.0.0.1:60000`) CheckSingleConfigurationPresentsAndAddIfMissing(`AdminWebServerBinding`, `127.0.0.1:60000`)
CheckSingleConfigurationPresentsAndAddIfMissing(`AdminWebServerEnabled`, `True`) CheckSingleConfigurationPresentsAndAddIfMissing(`AdminWebServerEnabled`, `True`)
CheckSingleConfigurationPresentsAndAddIfMissing(`AdminWebServerPassword`, ``)
CheckSingleConfigurationPresentsAndAddIfMissing(`AdminWebServerUseTLS`, `False`)
CheckSingleConfigurationPresentsAndAddIfMissing(`AdminWebServerTLSCertificateName`, `certificateAdmin.pem`)
CheckSingleConfigurationPresentsAndAddIfMissing(`AdminWebServerTLSPrivateKey`, `privateKeyAdmin.pem`)
CheckSingleConfigurationPresentsAndAddIfMissing(`AdminWebServerReadTimeoutSeconds`, `10`) CheckSingleConfigurationPresentsAndAddIfMissing(`AdminWebServerReadTimeoutSeconds`, `10`)
CheckSingleConfigurationPresentsAndAddIfMissing(`AdminWebServerWriteTimeoutSeconds`, `10`) CheckSingleConfigurationPresentsAndAddIfMissing(`AdminWebServerWriteTimeoutSeconds`, `10`)
CheckSingleConfigurationPresentsAndAddIfMissing(`AdminWebServerMaxHeaderLenBytes`, `10485760`) CheckSingleConfigurationPresentsAndAddIfMissing(`AdminWebServerMaxHeaderLenBytes`, `10485760`)
CheckSingleConfigurationPresentsAndAddIfMissing(`PublicWebServerPort`, `50000`) CheckSingleConfigurationPresentsAndAddIfMissing(`PublicWebServerPort`, `50000`)
CheckSingleConfigurationPresentsAndAddIfMissing(`PublicWebServerHostname`, `www.my-site.domain`)
CheckSingleConfigurationPresentsAndAddIfMissing(`PublicWebServerReadTimeoutSeconds`, `10`) CheckSingleConfigurationPresentsAndAddIfMissing(`PublicWebServerReadTimeoutSeconds`, `10`)
CheckSingleConfigurationPresentsAndAddIfMissing(`PublicWebServerWriteTimeoutSeconds`, `10`) CheckSingleConfigurationPresentsAndAddIfMissing(`PublicWebServerWriteTimeoutSeconds`, `10`)
CheckSingleConfigurationPresentsAndAddIfMissing(`PublicWebServerMaxHeaderLenBytes`, `1048576`) CheckSingleConfigurationPresentsAndAddIfMissing(`PublicWebServerMaxHeaderLenBytes`, `1048576`)
CheckSingleConfigurationPresentsAndAddIfMissing(`PublicWebServerUseTLS`, `False`)
CheckSingleConfigurationPresentsAndAddIfMissing(`PublicWebServerTLSCertificateName`, `certificatePublic.pem`)
CheckSingleConfigurationPresentsAndAddIfMissing(`PublicWebServerTLSPrivateKey`, `privateKeyPublic.pem`)
CheckSingleConfigurationPresentsAndAddIfMissing(`InternalCommPassword`, `please replace this with e.g. a random GUID, etc.`) CheckSingleConfigurationPresentsAndAddIfMissing(`InternalCommPassword`, `please replace this with e.g. a random GUID, etc.`)
CheckSingleConfigurationPresentsAndAddIfMissing(`CustomerDBHost`, `localhost:27017`) CheckSingleConfigurationPresentsAndAddIfMissing(`CustomerDBHost`, `localhost:27017`)
CheckSingleConfigurationPresentsAndAddIfMissing(`CustomerDBDatabase`, `Ocean`) CheckSingleConfigurationPresentsAndAddIfMissing(`CustomerDBDatabase`, `Ocean`)

View File

@ -14,7 +14,7 @@ func connectDatabase(config Meta.Configuration) {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
fmt.Printf("[Error] Was not able to connect to the configuration database: %s. Please read https://github.com/SommerEngineering/Ocean.\n", err) fmt.Printf("[Error] Was not able to connect to the configuration database: %s. Please read https://github.com/SommerEngineering/Ocean.\n", err)
os.Exit(0) os.Exit(1)
} }
}() }()
@ -22,7 +22,7 @@ func connectDatabase(config Meta.Configuration) {
if newSession, errDial := mgo.Dial(config.ConfigDBHostname); errDial != nil { if newSession, errDial := mgo.Dial(config.ConfigDBHostname); errDial != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNameDATABASE, `It was not possible to connect to the MongoDB host `+config.ConfigDBHostname, errDial.Error()) Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNameDATABASE, `It was not possible to connect to the MongoDB host `+config.ConfigDBHostname, errDial.Error())
fmt.Printf("[Error] Was not able to connect to the configuration database: %s. Please read https://github.com/SommerEngineering/Ocean.\n", errDial.Error()) fmt.Printf("[Error] Was not able to connect to the configuration database: %s. Please read https://github.com/SommerEngineering/Ocean.\n", errDial.Error())
os.Exit(0) os.Exit(1)
} else { } else {
session = newSession session = newSession
} }
@ -34,7 +34,7 @@ func connectDatabase(config Meta.Configuration) {
if errLogin := db.Login(config.ConfigDBConfigurationCollectionUsername, config.ConfigDBConfigurationCollectionPassword); errLogin != nil { if errLogin := db.Login(config.ConfigDBConfigurationCollectionUsername, config.ConfigDBConfigurationCollectionPassword); errLogin != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelSECURITY, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNameDATABASE, `It was not possible to login the user `+config.ConfigDBConfigurationCollectionUsername, errLogin.Error()) Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelSECURITY, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNameDATABASE, `It was not possible to login the user `+config.ConfigDBConfigurationCollectionUsername, errLogin.Error())
fmt.Printf("[Error] Was not able to connect to the configuration database: %s. Please read https://github.com/SommerEngineering/Ocean.\n", errLogin.Error()) fmt.Printf("[Error] Was not able to connect to the configuration database: %s. Please read https://github.com/SommerEngineering/Ocean.\n", errLogin.Error())
os.Exit(0) os.Exit(1)
} }
// In case of write operations, wait for the majority of servers to be done: // In case of write operations, wait for the majority of servers to be done:

View File

@ -13,7 +13,7 @@ func connectDatabase(host, username, password, database string) {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
fmt.Printf("[Error] Was not able to connect to the customer database: %s. Please read https://github.com/SommerEngineering/Ocean.\n", err) fmt.Printf("[Error] Was not able to connect to the customer database: %s. Please read https://github.com/SommerEngineering/Ocean.\n", err)
os.Exit(0) os.Exit(2)
} }
}() }()
@ -21,7 +21,7 @@ func connectDatabase(host, username, password, database string) {
if newSession, errDial := mgo.Dial(host); errDial != nil { if newSession, errDial := mgo.Dial(host); errDial != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNameDATABASE, `It was not possible to connect to the MongoDB host `+host, errDial.Error()) Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNameDATABASE, `It was not possible to connect to the MongoDB host `+host, errDial.Error())
fmt.Printf("[Error] Was not able to connect to the customer database: %s. Please read https://github.com/SommerEngineering/Ocean.\n", errDial.Error()) fmt.Printf("[Error] Was not able to connect to the customer database: %s. Please read https://github.com/SommerEngineering/Ocean.\n", errDial.Error())
os.Exit(0) os.Exit(2)
} else { } else {
mainSession = newSession mainSession = newSession
} }
@ -31,14 +31,14 @@ func connectDatabase(host, username, password, database string) {
if db == nil { if db == nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityCritical, LM.ImpactCritical, LM.MessageNameDATABASE, `Was not able to get the customer database.`) Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityCritical, LM.ImpactCritical, LM.MessageNameDATABASE, `Was not able to get the customer database.`)
fmt.Printf("[Error] Was not able to connect to the customer database. Please read https://github.com/SommerEngineering/Ocean.\n") fmt.Printf("[Error] Was not able to connect to the customer database. Please read https://github.com/SommerEngineering/Ocean.\n")
os.Exit(0) os.Exit(2)
} }
// Login: // Login:
if errLogin := db.Login(username, password); errLogin != nil { if errLogin := db.Login(username, password); errLogin != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelSECURITY, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNameDATABASE, `It was not possible to login the user `+databaseUsername, errLogin.Error()) Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelSECURITY, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNameDATABASE, `It was not possible to login the user `+databaseUsername, errLogin.Error())
fmt.Printf("[Error] Was not able to connect to the customer database: %s. Please read https://github.com/SommerEngineering/Ocean.\n", errLogin.Error()) fmt.Printf("[Error] Was not able to connect to the customer database: %s. Please read https://github.com/SommerEngineering/Ocean.\n", errLogin.Error())
os.Exit(0) os.Exit(2)
} }
// In case of write operations, wait for the majority of servers to be done: // In case of write operations, wait for the majority of servers to be done:
@ -53,7 +53,7 @@ func connectDatabase(host, username, password, database string) {
if gridFS == nil { if gridFS == nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityCritical, LM.ImpactCritical, LM.MessageNameDATABASE, `Was not able to get the GridFS from the database.`) Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityCritical, LM.ImpactCritical, LM.MessageNameDATABASE, `Was not able to get the GridFS from the database.`)
fmt.Printf("[Error] Was not able to connect to the customer database. Please read https://github.com/SommerEngineering/Ocean.\n") fmt.Printf("[Error] Was not able to connect to the customer database. Please read https://github.com/SommerEngineering/Ocean.\n")
os.Exit(0) os.Exit(2)
} }
// Ensure the indexes for the GridFS: // Ensure the indexes for the GridFS:

View File

@ -2,9 +2,11 @@ package Handlers
import ( import (
"fmt" "fmt"
"net/http"
"github.com/SommerEngineering/Ocean/ConfigurationDB"
"github.com/SommerEngineering/Ocean/Log" "github.com/SommerEngineering/Ocean/Log"
LM "github.com/SommerEngineering/Ocean/Log/Meta" LM "github.com/SommerEngineering/Ocean/Log/Meta"
"net/http"
) )
// Function to add a new public handler. // Function to add a new public handler.
@ -32,5 +34,5 @@ func AddAdminHandler(pattern string, handler func(http.ResponseWriter, *http.Req
}() }()
// Add the handler: // Add the handler:
muxAdmin.HandleFunc(pattern, handler) muxAdmin.HandleFunc(pattern, BasicAuth(handler, `admin`, ConfigurationDB.Read(`AdminWebServerPassword`), `Please enter your username and password for this site`))
} }

30
Handlers/BasicAuth.go Normal file
View File

@ -0,0 +1,30 @@
package Handlers
import (
"crypto/subtle"
"net/http"
)
// BasicAuth wraps a handler requiring HTTP basic auth for it using the given
// username and password and the specified realm, which shouldn't contain quotes.
//
// Most web browser display a dialog with something like:
//
// The website says: "<realm>"
//
// Which is really stupid so you may want to set the realm to a message rather than
// an actual realm.
//
// Taken from on http://stackoverflow.com/questions/21936332/idiomatic-way-of-requiring-http-basic-auth-in-go/39591234#39591234
func BasicAuth(handler http.HandlerFunc, username, password, realm string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
user, pass, ok := r.BasicAuth()
if !ok || subtle.ConstantTimeCompare([]byte(user), []byte(username)) != 1 || subtle.ConstantTimeCompare([]byte(pass), []byte(password)) != 1 {
w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`)
w.WriteHeader(401)
w.Write([]byte(http.StatusText(401)))
return
}
handler(w, r)
}
}

View File

@ -56,7 +56,7 @@ func ICCCHandler(response http.ResponseWriter, request *http.Request) {
if listener == nil { if listener == nil {
// Case: No such listener // Case: No such listener
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelWARN, LM.SeverityCritical, LM.ImpactUnknown, LM.MessageNameCONFIGURATION, `Was not able to find the correct listener for these ICCC message.`, `channel=`+channel, `command`+command, `hostname=`+Tools.ThisHostname()) Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelWARN, LM.SeverityCritical, LM.ImpactUnknown, LM.MessageNameCONFIGURATION, `Was not able to find the correct listener for these ICCC message.`, `channel=`+channel, `command=`+command, `hostname=`+Tools.ThisHostname())
http.NotFound(response, request) http.NotFound(response, request)
} else { } else {
// Case: Everything is fine => deliver the message and read the answer: // Case: Everything is fine => deliver the message and read the answer:

View File

@ -2,9 +2,11 @@ package ICCC
import ( import (
"container/list" "container/list"
"github.com/SommerEngineering/Ocean/ConfigurationDB"
"github.com/SommerEngineering/Ocean/Log" "github.com/SommerEngineering/Ocean/Log"
LM "github.com/SommerEngineering/Ocean/Log/Meta" LM "github.com/SommerEngineering/Ocean/Log/Meta"
"github.com/SommerEngineering/Ocean/Tools" "github.com/SommerEngineering/Ocean/Tools"
"strings"
) )
// Init this package. // Init this package.
@ -22,6 +24,13 @@ func init() {
// Using the local IP address: // Using the local IP address:
correctAddressWithPort = Tools.LocalIPAddressAndPort() correctAddressWithPort = Tools.LocalIPAddressAndPort()
// Determine the correct protocol:
if publicTLSEnabled := ConfigurationDB.Read(`PublicWebServerUseTLS`); strings.ToLower(publicTLSEnabled) == `true` {
activeProtocol = "https://"
} else {
activeProtocol = "http://"
}
// Init the database: // Init the database:
initDB() initDB()

View File

@ -2,6 +2,7 @@ package ICCC
import ( import (
"fmt" "fmt"
"github.com/SommerEngineering/Ocean/ConfigurationDB"
"github.com/SommerEngineering/Ocean/ICCC/Scheme" "github.com/SommerEngineering/Ocean/ICCC/Scheme"
"github.com/SommerEngineering/Ocean/Log" "github.com/SommerEngineering/Ocean/Log"
LM "github.com/SommerEngineering/Ocean/Log/Meta" LM "github.com/SommerEngineering/Ocean/Log/Meta"
@ -10,7 +11,7 @@ import (
// The internal function to register an listener to ICCC. // The internal function to register an listener to ICCC.
func registerListener2Database(channel, command, ipAddressPort string, isActive bool, kind byte) { func registerListener2Database(channel, command, ipAddressPort string, isActive bool, kind byte) {
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `Register this ICCC command in to the database.`, `channel=`+channel, `command=`+command, `IPAddressPort=`+ipAddressPort, fmt.Sprintf("isActive=%v", isActive)) Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `Register this ICCC command in to the database.`, `channel=`+channel, `command=`+command, `IPAddressPort=`+ipAddressPort, fmt.Sprintf("isActive=%v", isActive), `Hostname=`+ConfigurationDB.Read(`PublicWebServerHostname`))
entry := Scheme.Listener{} entry := Scheme.Listener{}
entry.Channel = channel entry.Channel = channel
@ -18,28 +19,29 @@ func registerListener2Database(channel, command, ipAddressPort string, isActive
entry.IsActive = isActive entry.IsActive = isActive
entry.IPAddressPort = ipAddressPort entry.IPAddressPort = ipAddressPort
entry.Kind = kind entry.Kind = kind
entry.Hostname = ConfigurationDB.Read(`PublicWebServerHostname`)
// //
// Case: Exists? // Case: Exists?
// //
selection := bson.D{{`Channel`, channel}, {`Command`, command}, {`IPAddressPort`, ipAddressPort}} selection := bson.D{{`Channel`, channel}, {`Command`, command}, {`IPAddressPort`, ipAddressPort}, {`Hostname`, entry.Hostname}}
count1, _ := collectionListener.Find(selection).Count() count1, _ := collectionListener.Find(selection).Count()
if count1 == 1 { if count1 == 1 {
// //
// Case: Exist but maybe not active // Case: Exist but maybe not active
// //
collectionListener.Update(selection, entry) collectionListener.Update(selection, entry)
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameCONFIGURATION, `Updating the existing ICCC command.`, `channel=`+channel, `command=`+command, `IPAddressPort=`+ipAddressPort) Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameCONFIGURATION, `Updating the existing ICCC command.`, `channel=`+channel, `command=`+command, `IPAddressPort=`+ipAddressPort, `Hostname=`+ConfigurationDB.Read(`PublicWebServerHostname`))
return return
} }
// //
// Case: Not exist // Case: Not exist
// //
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelWARN, LM.SeverityCritical, LM.ImpactNone, LM.MessageNameCONFIGURATION, `This ICCC command is not known.`, `Create now a new entry!`, `channel=`+channel, `command=`+command, `IPAddressPort=`+ipAddressPort) Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelWARN, LM.SeverityCritical, LM.ImpactNone, LM.MessageNameCONFIGURATION, `This ICCC command is not known.`, `Create now a new entry!`, `channel=`+channel, `command=`+command, `IPAddressPort=`+ipAddressPort, `Hostname=`+ConfigurationDB.Read(`PublicWebServerHostname`))
if err := collectionListener.Insert(entry); err != nil { if err := collectionListener.Insert(entry); err != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityCritical, LM.ImpactCritical, LM.MessageNameDATABASE, `It was not possible to add this ICCC command!`, err.Error(), `channel=`+channel, `command=`+command, `IPAddressPort=`+ipAddressPort) Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityCritical, LM.ImpactCritical, LM.MessageNameDATABASE, `It was not possible to add this ICCC command!`, err.Error(), `channel=`+channel, `command=`+command, `IPAddressPort=`+ipAddressPort, `Hostname=`+ConfigurationDB.Read(`PublicWebServerHostname`))
} else { } else {
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameCONFIGURATION, `This ICCC command is now known and active.`, `channel=`+channel, `command=`+command, `IPAddressPort=`+ipAddressPort) Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameCONFIGURATION, `This ICCC command is now known and active.`, `channel=`+channel, `command=`+command, `IPAddressPort=`+ipAddressPort, `Hostname=`+ConfigurationDB.Read(`PublicWebServerHostname`))
} }
} }

View File

@ -7,4 +7,5 @@ type Listener struct {
IsActive bool `bson:"IsActive"` IsActive bool `bson:"IsActive"`
IPAddressPort string `bson:"IPAddressPort"` IPAddressPort string `bson:"IPAddressPort"`
Kind byte `bson:"Kind"` Kind byte `bson:"Kind"`
Hostname string `bson:"Hostname"`
} }

View File

@ -16,7 +16,7 @@ func sendMessage(listener Scheme.Listener, data map[string][]string) (result map
valuesHTTP := signMessage(data) valuesHTTP := signMessage(data)
// Try to deliver the message: // Try to deliver the message:
if response, err := http.PostForm(`http://`+listener.IPAddressPort+`/ICCC`, valuesHTTP); err != nil { if response, err := http.PostForm(activeProtocol+listener.Hostname+`/ICCC`, valuesHTTP); err != nil {
// Case: Was not possible to deliver. // Case: Was not possible to deliver.
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityCritical, LM.ImpactUnknown, LM.MessageNameNETWORK, `Was not able to send the ICCC message.`, err.Error()) Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityCritical, LM.ImpactUnknown, LM.MessageNameNETWORK, `Was not able to send the ICCC message.`, err.Error())
} else { } else {

View File

@ -37,4 +37,5 @@ var (
startCacheTimerLock sync.Mutex = sync.Mutex{} // Mutex for the start timer startCacheTimerLock sync.Mutex = sync.Mutex{} // Mutex for the start timer
cacheTimerRunning bool = false // Is the timer running? cacheTimerRunning bool = false // Is the timer running?
correctAddressWithPort string = `` // The IP address and port of the this local server correctAddressWithPort string = `` // The IP address and port of the this local server
activeProtocol string = `http://`
) )

View File

@ -18,7 +18,7 @@ func initDatabase() {
defer func() { defer func() {
if err := recover(); err != nil { if err := recover(); err != nil {
fmt.Printf("[Error] Was not able to connect to the logging database: %s. Please read https://github.com/SommerEngineering/Ocean.\n", err) fmt.Printf("[Error] Was not able to connect to the logging database: %s. Please read https://github.com/SommerEngineering/Ocean.\n", err)
os.Exit(0) os.Exit(2)
} }
}() }()
@ -57,7 +57,7 @@ func initDatabase() {
if newSession, errDial := mgo.Dial(databaseHost); errDial != nil { if newSession, errDial := mgo.Dial(databaseHost); errDial != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNameDATABASE, `It was not possible to connect to the MongoDB host `+databaseHost, errDial.Error()) Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNameDATABASE, `It was not possible to connect to the MongoDB host `+databaseHost, errDial.Error())
fmt.Printf("[Error] Was not able to connect to the logging database: %s. Please read https://github.com/SommerEngineering/Ocean.\n", errDial.Error()) fmt.Printf("[Error] Was not able to connect to the logging database: %s. Please read https://github.com/SommerEngineering/Ocean.\n", errDial.Error())
os.Exit(0) os.Exit(2)
} else { } else {
logDBSession = newSession logDBSession = newSession
} }
@ -69,7 +69,7 @@ func initDatabase() {
if errLogin := logDB.Login(databaseUsername, databasePassword); errLogin != nil { if errLogin := logDB.Login(databaseUsername, databasePassword); errLogin != nil {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelSECURITY, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNameDATABASE, `It was not possible to login the user `+databaseUsername, errLogin.Error()) Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelSECURITY, LM.SeverityUnknown, LM.ImpactUnknown, LM.MessageNameDATABASE, `It was not possible to login the user `+databaseUsername, errLogin.Error())
fmt.Printf("[Error] Was not able to connect to the logging database: %s. Please read https://github.com/SommerEngineering/Ocean.\n", errLogin.Error()) fmt.Printf("[Error] Was not able to connect to the logging database: %s. Please read https://github.com/SommerEngineering/Ocean.\n", errLogin.Error())
os.Exit(0) os.Exit(2)
} }
// Get the collection: // Get the collection:

BIN
Ocean.pdf

Binary file not shown.

View File

@ -91,7 +91,10 @@ exit
* Finnaly, start Ocean again. The system should now run fine. Please have a look at the ICCC startup logging messages. * Finnaly, start Ocean again. The system should now run fine. Please have a look at the ICCC startup logging messages.
### Use Ocean as distributed messaging broker ### Use Ocean as distributed messaging broker
For this case, you can now start your other ICCC components. This are e.g. some Java, Python or C# programs which are using the Ocean ICCC drivers. These drivers currently under development and they will be available soon. For this case, you can now start your other ICCC components. This are e.g. some Java, Python or C# programs which are using the Ocean ICCC drivers. These drivers currently under development and they will be available soon. **The next priority:** OceanPy, the ICCC driver for Python.
**Available ICCC drivers:**
- [OceanNET - ICCC with .NET and C#](https://github.com/SommerEngineering/OceanNET)
### Use Ocean as framework e.g. for websites ### Use Ocean as framework e.g. for websites
For this case, an example project with documentation is available here: https://github.com/SommerEngineering/Example003 For this case, an example project with documentation is available here: https://github.com/SommerEngineering/Example003

View File

@ -3,10 +3,12 @@ package StaticFiles
import ( import (
"archive/zip" "archive/zip"
"bytes" "bytes"
"github.com/SommerEngineering/Ocean/ConfigurationDB"
"github.com/SommerEngineering/Ocean/Log" "github.com/SommerEngineering/Ocean/Log"
LM "github.com/SommerEngineering/Ocean/Log/Meta" LM "github.com/SommerEngineering/Ocean/Log/Meta"
"github.com/SommerEngineering/Ocean/Shutdown" "github.com/SommerEngineering/Ocean/Shutdown"
"io/ioutil" "io/ioutil"
"strings"
) )
// Try to read a static file. // Try to read a static file.
@ -17,6 +19,40 @@ func FindAndReadFile(filename string) (result []byte) {
return return
} }
//
// Ensure that the TLS keys are secure and save:
//
if strings.ToLower(filename) == strings.ToLower(ConfigurationDB.Read(`AdminWebServerTLSCertificateName`)) {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelSECURITY, LM.SeverityNone, LM.ImpactNone, LM.MessageNameREQUEST, `Someone tried to read the TLS certificate of the admin server. The attempt was inhibited.`)
return
}
if strings.ToLower(filename) == strings.ToLower(ConfigurationDB.Read(`AdminWebServerTLSPrivateKey`)) {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelSECURITY, LM.SeverityNone, LM.ImpactNone, LM.MessageNameREQUEST, `Someone tried to read the TLS certificate's private key of the admin server. The attempt was inhibited.`)
return
}
if strings.ToLower(filename) == strings.ToLower(ConfigurationDB.Read(`PublicWebServerTLSCertificateName`)) {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelSECURITY, LM.SeverityNone, LM.ImpactNone, LM.MessageNameREQUEST, `Someone tried to read the TLS certificate of the public server. The attempt was inhibited.`)
return
}
if strings.ToLower(filename) == strings.ToLower(ConfigurationDB.Read(`PublicWebServerTLSPrivateKey`)) {
Log.LogFull(senderName, LM.CategorySYSTEM, LM.LevelSECURITY, LM.SeverityNone, LM.ImpactNone, LM.MessageNameREQUEST, `Someone tried to read the TLS certificate's private key of the public server. The attempt was inhibited.`)
return
}
result = FindAndReadFileINTERNAL(filename)
return
}
func FindAndReadFileINTERNAL(filename string) (result []byte) {
// Case: The system goes down.
if Shutdown.IsDown() {
return
}
// Prepare the path: // Prepare the path:
path := filename path := filename

View File

@ -29,7 +29,7 @@ func icccComponentStartUpMessageReceiver(data map[string][]string) (result map[s
messageData := obj.(SystemMessages.ICCCComponentStartUpMessage) messageData := obj.(SystemMessages.ICCCComponentStartUpMessage)
// Provide a log entry: // Provide a log entry:
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `ICCC message: The external component is now up and ready.`, fmt.Sprintf("ipAddressPort=%s", messageData.IPAddressPort), fmt.Sprintf("name=", messageData.Name), fmt.Sprintf("version=", messageData.Version)) Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `ICCC message: The external component is now up and ready.`, fmt.Sprintf("ipAddressPort='%s'", messageData.IPAddressPort), fmt.Sprintf("name='%s'", messageData.Name), fmt.Sprintf("version='%s'", messageData.Version))
// An answer is necessary: // An answer is necessary:
return ICCC.Message2Data("", "", SystemMessages.AnswerACK) return ICCC.Message2Data("", "", SystemMessages.AnswerACK)

View File

@ -29,7 +29,7 @@ func icccOceanStartUpMessageReceiver(data map[string][]string) (result map[strin
messageData := obj.(SystemMessages.ICCCOceanStartUpMessage) messageData := obj.(SystemMessages.ICCCOceanStartUpMessage)
// Provide a log entry: // Provide a log entry:
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `ICCC message: The Ocean server is now up and ready.`, fmt.Sprintf("public server=%s", messageData.PublicIPAddressPort), fmt.Sprintf("admin server=%s", messageData.AdminIPAddressPort), fmt.Sprintf("Ocean's version=%s", messageData.OceanVersion)) Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `ICCC message: The Ocean server is now up and ready.`, fmt.Sprintf("public server='%s'", messageData.PublicIPAddressPort), fmt.Sprintf("admin server='%s'", messageData.AdminIPAddressPort), fmt.Sprintf("Ocean's version='%s'", messageData.OceanVersion))
// An answer is necessary: // An answer is necessary:
return ICCC.Message2Data("", "", SystemMessages.AnswerACK) return ICCC.Message2Data("", "", SystemMessages.AnswerACK)

View File

@ -105,7 +105,7 @@ func initSystem() {
ICCC.Registrar(ICCC.ChannelICCC, `ICCC::DeleteListener`, ICCC.ICCCDeleteListenerReceiver) ICCC.Registrar(ICCC.ChannelICCC, `ICCC::DeleteListener`, ICCC.ICCCDeleteListenerReceiver)
ICCC.Registrar(ICCC.ChannelICCC, `ICCC::DeleteHost`, ICCC.ICCCDeleteHostReceiver) ICCC.Registrar(ICCC.ChannelICCC, `ICCC::DeleteHost`, ICCC.ICCCDeleteHostReceiver)
ICCC.Registrar(ICCC.ChannelICCC, `ICCC::ListenerUpdate`, ICCC.ICCCListenerUpdateReceiver) ICCC.Registrar(ICCC.ChannelICCC, `ICCC::ListenerUpdate`, ICCC.ICCCListenerUpdateReceiver)
ICCC.Registrar(ICCC.ChannelICCC, `Ping::Ping`, ICCC.ICCCPingReceiver) ICCC.Registrar(ICCC.ChannelPING, `Ping::Ping`, ICCC.ICCCPingReceiver)
ICCC.Registrar(ICCC.ChannelSYSTEM, `System::Version`, ICCC.ICCCGetVersionReceiver) ICCC.Registrar(ICCC.ChannelSYSTEM, `System::Version`, ICCC.ICCCGetVersionReceiver)
ICCC.Registrar(ICCC.ChannelICCC, `ICCC::GetHosts`, ICCC.ICCCGetHostsReceiver) ICCC.Registrar(ICCC.ChannelICCC, `ICCC::GetHosts`, ICCC.ICCCGetHostsReceiver)
ICCC.Registrar(ICCC.ChannelICCC, `ICCC::GetListeners`, ICCC.ICCCGetListenersReceiver) ICCC.Registrar(ICCC.ChannelICCC, `ICCC::GetListeners`, ICCC.ICCCGetListenersReceiver)

View File

@ -1,5 +1,5 @@
package Version package Version
var ( var (
oceansVersion string = `2.0.4` // Ocean's current version oceansVersion string = `2.1.3` // Ocean's current version
) )

7
Templates/Add.go Normal file
View File

@ -0,0 +1,7 @@
package Templates
//AddTemplate adds a template to the template cache so it can be used by ProcessHTML
func AddTemplate(src string) error {
_, err := templates.Parse(src)
return err
}

View File

@ -20,6 +20,5 @@ func RandomFloat64() (rnd float64) {
// Gets a random UUID (v4). // Gets a random UUID (v4).
func RandomGUID() (guidString string) { func RandomGUID() (guidString string) {
guidString = uuid.NewV4().String() guidString = uuid.NewV4().String()
guidString = guidString[1 : len(guidString)-1]
return return
} }

View File

@ -6,8 +6,12 @@ import (
"github.com/SommerEngineering/Ocean/Handlers" "github.com/SommerEngineering/Ocean/Handlers"
"github.com/SommerEngineering/Ocean/Log" "github.com/SommerEngineering/Ocean/Log"
LM "github.com/SommerEngineering/Ocean/Log/Meta" LM "github.com/SommerEngineering/Ocean/Log/Meta"
"github.com/SommerEngineering/Ocean/StaticFiles"
"github.com/SommerEngineering/Ocean/Tools" "github.com/SommerEngineering/Ocean/Tools"
"io/ioutil"
"net/http" "net/http"
"os"
"path/filepath"
"strconv" "strconv"
"strings" "strings"
"time" "time"
@ -64,6 +68,32 @@ func init() {
serverPublic.MaxHeaderBytes = maxHeaderBytes serverPublic.MaxHeaderBytes = maxHeaderBytes
} }
// Is TLS configured?
if publicTLSEnabled := ConfigurationDB.Read(`PublicWebServerUseTLS`); strings.ToLower(publicTLSEnabled) == `true` {
// TLS is enabled. Copy the certificate and private key to the source directory.
publicTLSCertificate := StaticFiles.FindAndReadFileINTERNAL(ConfigurationDB.Read(`PublicWebServerTLSCertificateName`))
publicTLSPrivateKey := StaticFiles.FindAndReadFileINTERNAL(ConfigurationDB.Read(`PublicWebServerTLSPrivateKey`))
// Access to the working directory?
currentDir, dirError := os.Getwd()
if dirError != nil {
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.MessageNameCONFIGURATION, `Was not able to read the working directory. Thus, cannot store the TLS certificates!`, dirError.Error())
} else {
// Build the filenames:
pathCertificate := filepath.Join(currentDir, ConfigurationDB.Read(`PublicWebServerTLSCertificateName`))
pathPrivateKey := filepath.Join(currentDir, ConfigurationDB.Read(`PublicWebServerTLSPrivateKey`))
// Write the files:
if writeError := ioutil.WriteFile(pathCertificate, publicTLSCertificate, 0660); writeError != nil {
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.MessageNameCONFIGURATION, `Was not able to write the TLS certificate to the working directory.`, writeError.Error())
}
if writeError := ioutil.WriteFile(pathPrivateKey, publicTLSPrivateKey, 0660); writeError != nil {
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.MessageNameCONFIGURATION, `Was not able to write the TLS private key to the working directory.`, writeError.Error())
}
}
}
// Is the private web server (i.e. administration server) enabled? // Is the private web server (i.e. administration server) enabled?
if strings.ToLower(ConfigurationDB.Read(`AdminWebServerEnabled`)) == `true` { if strings.ToLower(ConfigurationDB.Read(`AdminWebServerEnabled`)) == `true` {
@ -105,6 +135,32 @@ func init() {
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameCONFIGURATION, fmt.Sprintf("The admin web server's max. header size was set to %d bytes.", maxHeaderBytes)) Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameCONFIGURATION, fmt.Sprintf("The admin web server's max. header size was set to %d bytes.", maxHeaderBytes))
serverAdmin.MaxHeaderBytes = maxHeaderBytes serverAdmin.MaxHeaderBytes = maxHeaderBytes
} }
// Is TLS configured?
if adminTLSEnabled := ConfigurationDB.Read(`AdminWebServerUseTLS`); strings.ToLower(adminTLSEnabled) == `true` {
// TLS is enabled. Copy the certificate and private key to the source directory.
adminTLSCertificate := StaticFiles.FindAndReadFileINTERNAL(ConfigurationDB.Read(`AdminWebServerTLSCertificateName`))
adminTLSPrivateKey := StaticFiles.FindAndReadFileINTERNAL(ConfigurationDB.Read(`AdminWebServerTLSPrivateKey`))
// Access to the working directory?
currentDir, dirError := os.Getwd()
if dirError != nil {
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.MessageNameCONFIGURATION, `Was not able to read the working directory. Thus, cannot store the TLS certificates!`, dirError.Error())
} else {
// Build the filenames:
pathCertificate := filepath.Join(currentDir, ConfigurationDB.Read(`AdminWebServerTLSCertificateName`))
pathPrivateKey := filepath.Join(currentDir, ConfigurationDB.Read(`AdminWebServerTLSPrivateKey`))
// Write the files:
if writeError := ioutil.WriteFile(pathCertificate, adminTLSCertificate, 0660); writeError != nil {
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.MessageNameCONFIGURATION, `Was not able to write the TLS certificate to the working directory.`, writeError.Error())
}
if writeError := ioutil.WriteFile(pathPrivateKey, adminTLSPrivateKey, 0660); writeError != nil {
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelERROR, LM.MessageNameCONFIGURATION, `Was not able to write the TLS private key to the working directory.`, writeError.Error())
}
}
}
} else { } else {
// Private web server is disabled: // Private web server is disabled:
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `The admin web server is disabled.`) Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `The admin web server is disabled.`)

View File

@ -2,11 +2,13 @@ package WebServer
import ( import (
"fmt" "fmt"
"github.com/SommerEngineering/Ocean/ConfigurationDB"
"github.com/SommerEngineering/Ocean/ICCC" "github.com/SommerEngineering/Ocean/ICCC"
"github.com/SommerEngineering/Ocean/ICCC/SystemMessages" "github.com/SommerEngineering/Ocean/ICCC/SystemMessages"
"github.com/SommerEngineering/Ocean/Log" "github.com/SommerEngineering/Ocean/Log"
LM "github.com/SommerEngineering/Ocean/Log/Meta" LM "github.com/SommerEngineering/Ocean/Log/Meta"
"github.com/SommerEngineering/Ocean/System/Version" "github.com/SommerEngineering/Ocean/System/Version"
"strings"
) )
func Start() { func Start() {
@ -19,15 +21,28 @@ func Start() {
if serverPublic != nil { if serverPublic != nil {
data.PublicIPAddressPort = serverPublicAddressPort data.PublicIPAddressPort = serverPublicAddressPort
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `Public web server is now listening.`, `Configuration for hostname and port.`, serverPublicAddressPort) Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `Public web server is now listening.`, `Configuration for hostname and port.`, serverPublicAddressPort)
// Is TLS configured?
if publicTLSEnabled := ConfigurationDB.Read(`PublicWebServerUseTLS`); strings.ToLower(publicTLSEnabled) == `true` {
go serverPublic.ListenAndServeTLS(ConfigurationDB.Read(`PublicWebServerTLSCertificateName`), ConfigurationDB.Read(`PublicWebServerTLSPrivateKey`))
} else {
go serverPublic.ListenAndServe() go serverPublic.ListenAndServe()
} }
}
// Start the private web server: // Start the private web server:
if serverAdmin != nil { if serverAdmin != nil {
data.AdminIPAddressPort = serverAdminAddressPort data.AdminIPAddressPort = serverAdminAddressPort
Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `Admin web server is now listening.`, `Configuration for hostname and port.`, serverAdminAddressPort) Log.LogShort(senderName, LM.CategorySYSTEM, LM.LevelINFO, LM.MessageNameSTARTUP, `Admin web server is now listening.`, `Configuration for hostname and port.`, serverAdminAddressPort)
// Is TLS configured?
if adminTLSEnabled := ConfigurationDB.Read(`AdminWebServerUseTLS`); strings.ToLower(adminTLSEnabled) == `true` {
go serverAdmin.ListenAndServeTLS(ConfigurationDB.Read(`AdminWebServerTLSCertificateName`), ConfigurationDB.Read(`AdminWebServerTLSPrivateKey`))
} else {
go serverAdmin.ListenAndServe() go serverAdmin.ListenAndServe()
} }
}
// Notify the whole cluster, that this server is now up and ready: // Notify the whole cluster, that this server is now up and ready:
answers := ICCC.WriteMessage2All(ICCC.ChannelSTARTUP, `System::OceanStart`, ICCC.KindALL, data, SystemMessages.ICCCDefaultAnswer{}) answers := ICCC.WriteMessage2All(ICCC.ChannelSTARTUP, `System::OceanStart`, ICCC.KindALL, data, SystemMessages.ICCCDefaultAnswer{})