From af21b300eaf97965dcbe88e848b1187aeafc1660 Mon Sep 17 00:00:00 2001 From: Chteufleur Date: Mon, 18 Jul 2016 20:09:17 +0200 Subject: [PATCH] Send HTTP error code depending error that append. Change message content with something more user friendly --- README.md | 25 ++++++++++++++++++++----- http/http.go | 19 +++++++++++++++---- main.go | 7 +------ xmpp/client.go | 30 ++++++++++++++++++++++-------- xmpp/xmpp.go | 23 +++++++++++++++++++---- 5 files changed, 77 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 9ff3988..ff04284 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,8 @@ go get git.kingpenguin.tk/chteufleur/HTTPAuthentificationOverXMPP.git ``` ### Configure -Configure the gateway by editing the ``httpAuth.cfg`` file in order to give all XMPP component and HTTP server informations. An example of the config file can be found in [the repos](https://git.kingpenguin.tk/chteufleur/HTTPAuthentificationOverXMPP/src/master/httpAuth.cfg). +Configure the gateway by editing the ``httpAuth.cfg`` file in order to give all XMPP component and HTTP server informations. +An example of the config file can be found in [the repos](https://git.kingpenguin.tk/chteufleur/HTTPAuthentificationOverXMPP/src/master/httpAuth.cfg). XMPP * xmpp_server_address : Component server address connection (default: 127.0.0.1) @@ -35,18 +36,32 @@ HTTP ### Utilization To ask authorization, just send an HTTP request to the path ``/auth`` with parameters: - * jid : JID of the user (user@host/resource or user@host) - * domain : Domain you want to access - * method : Method you access the domain + * __jid__ : JID of the user (user@host/resource or user@host) + * __domain__ : Domain you want to access + * __method__ : Method you access the domain * transaction_id : Transaction identifier (auto generated if not provide) * timeout : Timeout of the request in second (default : 60, max : 300) +__Bold parameters__ are mandatory. + Example: ``` GET /auth?jid=user%40host%2fresource&domain=example.org&method=POST&transaction_id=WhatEverYouWant&timeout=120 HTTP/1.1 ``` -This will send a request to the given JID. If the user accept, the server will return HTTP code 200, otherwise it will return HTTP code 401. +This will send a request to the given JID, then return HTTP code depending on what appended. + * 200 : User accept the request + * 401 : User deny the request + * 504 : User do not provide an answer (timeout) + * 520 : Unknown error append + * 523 : Server is unreachable + + +If the provided JID contain a resource, it will try to send an ``iq`` stanza. +If the answer to this ``iq`` is a ``feature-not-implemented`` or ``service-unavailable`` error, +it will automatically send a ``message`` stanza. Unfortunately, if a ``message`` stanza is used, +their is probably no way to get the error if the JID does not exist or is unreachable. + A demo version can be found at [auth.xmpp.kingpenguin.tk](http://auth.xmpp.kingpenguin.tk) for test purpose only. diff --git a/http/http.go b/http/http.go index fd5695c..b8e4b52 100644 --- a/http/http.go +++ b/http/http.go @@ -27,6 +27,9 @@ const ( RETURN_VALUE_OK = "OK" RETURN_VALUE_NOK = "NOK" + + StatusUnknownError = 520 + StatusUnreachable = 523 ) var ( @@ -62,7 +65,7 @@ func authHandler(w http.ResponseWriter, r *http.Request) { timeout = MaxTimeout } - chanAnswer := make(chan bool) + chanAnswer := make(chan string) ChanRequest <- jid ChanRequest <- method @@ -72,13 +75,21 @@ func authHandler(w http.ResponseWriter, r *http.Request) { select { case answer := <-chanAnswer: - if answer { + switch answer { + case xmpp.REPLY_OK: w.WriteHeader(http.StatusOK) - } else { + + case xmpp.REPLY_DENY: w.WriteHeader(http.StatusUnauthorized) + + case xmpp.REPLY_UNREACHABLE: + w.WriteHeader(StatusUnreachable) + + default: + w.WriteHeader(StatusUnknownError) } case <-time.After(time.Duration(timeout) * time.Second): - w.WriteHeader(http.StatusUnauthorized) + w.WriteHeader(http.StatusGatewayTimeout) delete(xmpp.WaitMessageAnswers, transaction) } } diff --git a/main.go b/main.go index 343e6ee..f21d676 100644 --- a/main.go +++ b/main.go @@ -76,13 +76,8 @@ func request() { client.Domain = getChanString(http.ChanRequest) client.Transaction = getChanString(http.ChanRequest) - if client.Transaction == "" { - // Random transaction ID generation - client.Transaction = xmpp.SessionID() - } - chanResult := <-http.ChanRequest - if v, ok := chanResult.(chan bool); ok { + if v, ok := chanResult.(chan string); ok { client.ChanReply = v } diff --git a/xmpp/client.go b/xmpp/client.go index 64aed17..d229f3c 100644 --- a/xmpp/client.go +++ b/xmpp/client.go @@ -10,6 +10,10 @@ import ( const ( dictionary = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + + REPLY_UNREACHABLE = "reply_unreachable" + REPLY_DENY = "reply_deny" + REPLY_OK = "reply_ok" ) type Client struct { @@ -18,14 +22,20 @@ type Client struct { Domain string Transaction string - ChanReply chan bool + ChanReply chan string } func (client *Client) QueryClient() { log.Printf("%sQuery JID %s", LogInfo, client.JID) + isAutoGeneratedTranctionID := false + if client.Transaction == "" { + // Random transaction ID generation + client.Transaction = xmpp.SessionID() + isAutoGeneratedTranctionID = true + } clientJID, _ := xmpp.ParseJID(client.JID) if clientJID.Resource == "" { - client.askViaMessage() + client.askViaMessage(isAutoGeneratedTranctionID) } else { client.askViaIQ() } @@ -41,16 +51,20 @@ func (client *Client) askViaIQ() { comp.Out <- m } -func (client *Client) askViaMessage() { - m := xmpp.Message{From: jid.Domain, To: client.JID, Type: "normal"} +func (client *Client) askViaMessage(isAutoGeneratedTranctionID bool) { + m := xmpp.Message{From: jid.Domain, To: client.JID, Type: xmpp.MessageTypeNormal} m.Thread = xmpp.SessionID() - m.Body = "HTTP (" + client.Method + ") Authorization for " + client.Domain + " (id: " + client.Transaction + ")." - m.Body += "\nReply to this message to confirm the request." - m.Body += "\nIf your client doesn't support that functionnality, please send back the identifier to confirm the request." + m.Body = client.Domain + " (with method " + client.Method + ") need to validate your identity, do you agree ?" + m.Body += "\nValidation code : " + client.Transaction + if !isAutoGeneratedTranctionID { + // Send only if the transaction ID is not autogenerated + m.Body += "\nPlease check that this code is the same as on " + client.Domain + } + m.Body += "\n\nIf your client doesn't support that functionnality, please send back the validation code to confirm the request." m.Confir = &xmpp.Confirm{Id: client.Transaction, Method: client.Method, URL: client.Domain} - log.Printf("%sSenp message %v", LogInfo, m) + log.Printf("%sSend message %v", LogInfo, m) WaitMessageAnswers[client.Transaction] = client comp.Out <- m } diff --git a/xmpp/xmpp.go b/xmpp/xmpp.go index e81c3c1..7ed4e84 100644 --- a/xmpp/xmpp.go +++ b/xmpp/xmpp.go @@ -116,17 +116,32 @@ func processConfirm(x interface{}, client *Client) { if client != nil { if mesOK && mes.Error != nil { - client.ChanReply <- false + // Message error + errCondition := mes.Error.Condition() + if errCondition == xmpp.ServiceUnavailable { + // unreachable + client.ChanReply <- REPLY_UNREACHABLE + } else { + client.ChanReply <- REPLY_DENY + } + } else if iqOK && iq.Error != nil { - if iq.Error.Condition().Local == "service-unavailable" { + // IQ error + errCondition := iq.Error.Condition() + if errCondition == xmpp.ServiceUnavailable || errCondition == xmpp.FeatureNotImplemented { // send by message if client doesn't implemente it client.JID = strings.SplitN(client.JID, "/", 2)[0] go client.QueryClient() + } else if errCondition == xmpp.RemoteServerNotFound { + // unreachable + client.ChanReply <- REPLY_UNREACHABLE } else { - client.ChanReply <- false + client.ChanReply <- REPLY_DENY } + } else { - client.ChanReply <- true + // No error + client.ChanReply <- REPLY_OK } } }