Skip to content

Commit

Permalink
WebFrontend: Expose some session information (username etc) to scripts.
Browse files Browse the repository at this point in the history
  • Loading branch information
stuartm committed Feb 25, 2015
1 parent 9786ddf commit e23f1a3
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 10 deletions.
10 changes: 10 additions & 0 deletions mythtv/html/backend_index.qsp
Expand Up @@ -41,6 +41,16 @@ $(document).keyup(function(e) {
<div id="header_logo">
<a href="/"><img src="/images/mythtv.png" class="png" width="180" height="64" border="0" alt="MythTV"></a>
</div>
<div id="header_login">
<%if (Session.userid > 0) { %>
Logged in as <span id="session_username"><%=Session.username%></span>
<%
}
else {
%>
<!-- <a href="">Login</a> -->
<%}%>
</div>
</div>

<div id="menu-tab" onMouseOver="showMainMenu()">
Expand Down
9 changes: 9 additions & 0 deletions mythtv/html/css/site.css
Expand Up @@ -225,6 +225,15 @@
height: 36px;
}

#header_login {
float: right;
margin-right: 10px;
}

#session_username {
font-weight: bold;
}

#content {
position: absolute;
top: 36px;
Expand Down
44 changes: 34 additions & 10 deletions mythtv/libs/libmythupnp/httprequest.cpp
Expand Up @@ -1363,6 +1363,17 @@ bool HTTPRequest::ParseRequest()
return true;
}

// Allow session resumption for TLS connections
if (m_mapCookies.contains("sessionToken"))
{
QString sessionToken = m_mapCookies["sessionToken"];
MythSessionManager *sessionManager = gCoreContext->GetSessionManager();
MythUserSession session = sessionManager->GetSession(sessionToken);

if (session.IsValid())
m_userSession = session;
}

m_bProtected = false;

if (IsUrlProtected( m_sBaseUrl ))
Expand Down Expand Up @@ -1845,6 +1856,10 @@ bool HTTPRequest::IsUrlProtected( const QString &sBaseUrl )
return false;
}

/////////////////////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////////////////

QString HTTPRequest::GetAuthenticationHeader(bool isStale)
{
QString authHeader;
Expand All @@ -1871,6 +1886,10 @@ QString HTTPRequest::GetAuthenticationHeader(bool isStale)
return authHeader;
}

/////////////////////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////////////////

QString HTTPRequest::CalculateDigestNonce(const QString& timeStamp)
{
QString uniqueID = QString("%1:%2").arg(timeStamp).arg(m_sPrivateToken);
Expand All @@ -1879,6 +1898,10 @@ QString HTTPRequest::CalculateDigestNonce(const QString& timeStamp)
return nonce;
}

/////////////////////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////////////////

bool HTTPRequest::BasicAuthentication()
{
LOG(VB_HTTP, LOG_NOTICE, "Attempting HTTP Basic Authentication");
Expand Down Expand Up @@ -1926,9 +1949,15 @@ bool HTTPRequest::BasicAuthentication()
SetCookie("sessionToken", session.GetSessionToken(),
session.GetSessionExpires(), true);

m_userSession = session;

return false;
}

/////////////////////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////////////////

bool HTTPRequest::DigestAuthentication()
{
LOG(VB_HTTP, LOG_NOTICE, "Attempting HTTP Digest Authentication");
Expand Down Expand Up @@ -2070,6 +2099,8 @@ bool HTTPRequest::DigestAuthentication()
SetCookie("sessionToken", session.GetSessionToken(),
session.GetSessionExpires(), true);

m_userSession = session;

return true;
}
else
Expand All @@ -2089,16 +2120,9 @@ bool HTTPRequest::DigestAuthentication()

bool HTTPRequest::Authenticated()
{
// Allow session resumption for TLS connections
if (m_mapCookies.contains("sessionToken"))
{
QString sessionToken = m_mapCookies["sessionToken"];
MythSessionManager *sessionManager = gCoreContext->GetSessionManager();
MythUserSession session = sessionManager->GetSession(sessionToken);

if (session.IsValid())
return true;
}
// Check if the existing user has permission to access this resource
if (m_userSession.IsValid()) //m_userSession.CheckPermission())
return true;

QStringList oList = m_mapHeaders[ "authorization" ].split( ' ' );

Expand Down
3 changes: 3 additions & 0 deletions mythtv/libs/libmythupnp/httprequest.h
Expand Up @@ -20,6 +20,8 @@
#include <QTcpSocket>
#include <QDateTime>

#include "mythsession.h"

#include "upnpexp.h"
#include "upnputil.h"
#include "serializers/serializer.h"
Expand Down Expand Up @@ -144,6 +146,7 @@ class UPNP_PUBLIC HTTPRequest
IPostProcess *m_pPostProcess;

QString m_sPrivateToken;
MythUserSession m_userSession;

private:

Expand Down
39 changes: 39 additions & 0 deletions mythtv/libs/libmythupnp/serverSideScripting.cpp
Expand Up @@ -18,6 +18,7 @@

#include "serverSideScripting.h"
#include "mythlogging.h"
#include <mythsession.h>
#include "httpserver.h"

QScriptValue formatStr(QScriptContext *context, QScriptEngine *interpreter);
Expand Down Expand Up @@ -282,6 +283,25 @@ bool ServerSideScripting::EvaluatePage( QTextStream *pOutStream, const QString &
requestHeaders.insert(key, value);
}

// ------------------------------------------------------------------
// Build array of cookies
// ------------------------------------------------------------------

QStringMap mapCookies = pRequest->m_mapCookies;

QVariantMap requestCookies;
for (it = mapCookies.begin(); it != mapCookies.end(); ++it)
{
QString key = it.key();
key = key.replace('-', '_'); // May be other valid chars in a request header that we need to replace
QVariant value = QVariant(it.value());

if (!validChars.exactMatch(key)) // Discard anything that isn't valid for now
continue;

requestCookies.insert(key, value);
}

// ------------------------------------------------------------------
// Build array of information from the server e.g. client IP
// See RFC 3875 - The Common Gateway Interface
Expand Down Expand Up @@ -322,6 +342,23 @@ bool ServerSideScripting::EvaluatePage( QTextStream *pOutStream, const QString &
serverVars.insert("CLIENT_NETWORK", "remote");
}

// ------------------------------------------------------------------
// User Session information
//
// SECURITY
// The session token and password digest are considered sensitive on
// unencrypted connections and therefore must never be included in the
// HTML. An intercepted session token or password digest can be used
// to login or hijack an existing session.
// ------------------------------------------------------------------
MythUserSession session = pRequest->m_userSession;
QVariantMap sessionVars;
sessionVars.insert("username", session.GetUserName());
sessionVars.insert("userid", session.GetUserId());
sessionVars.insert("created", session.GetSessionCreated());
sessionVars.insert("lastactive", session.GetSessionLastActive());
sessionVars.insert("expires", session.GetSessionExpires());

// ------------------------------------------------------------------
// Add the arrays (objects) we've just created to the global scope
// They may be accessed as 'Server.REMOTE_ADDR'
Expand All @@ -336,6 +373,8 @@ bool ServerSideScripting::EvaluatePage( QTextStream *pOutStream, const QString &
m_engine.toScriptValue(respHeaderMap));
m_engine.globalObject().setProperty("Server",
m_engine.toScriptValue(serverVars));
m_engine.globalObject().setProperty("Session",
m_engine.toScriptValue(sessionVars));
QScriptValue qsCspToken = m_engine.toScriptValue(cspToken);
m_engine.globalObject().setProperty("CSP_NONCE", qsCspToken);

Expand Down

0 comments on commit e23f1a3

Please sign in to comment.