Bug 758258 - part 3 - Add extendedOrigin, appStatus and appId to nsIPrincipal. r=bholley sr=sicking

This commit is contained in:
Mounir Lamouri 2012-07-19 22:44:03 -07:00
parent 63b5f77065
commit 69029dd83f
9 changed files with 293 additions and 90 deletions

View File

@ -21,7 +21,7 @@ interface nsIContentSecurityPolicy;
[ptr] native JSPrincipals(JSPrincipals);
[ptr] native PrincipalArray(nsTArray<nsCOMPtr<nsIPrincipal> >);
[scriptable, uuid(42ba6a38-d619-49ab-8248-3d247e959d5e)]
[scriptable, uuid(fbb93cc7-9a94-4743-8e89-9e6939cac083)]
interface nsIPrincipal : nsISerializable
{
/**
@ -212,6 +212,39 @@ interface nsIPrincipal : nsISerializable
* A Content Security Policy associated with this principal.
*/
[noscript] attribute nsIContentSecurityPolicy csp;
/**
* Returns the extended origin of the principal.
* The extended origin is a string that has more information than the origin
* and can be used to isolate data or permissions between different
* principals while taking into account parameters like the app id or the
* fact that the principal is embedded in a mozbrowser.
* Some principals will return the origin for extendedOrigin.
* Some principals will assert if you try to access the extendedOrigin.
*
* The extendedOrigin is intended to be an opaque identifier. It is
* currently "human-readable" but no callers should assume it will stay
* as is and it might be crypto-hashed at some point.
*/
readonly attribute AUTF8String extendedOrigin;
const short APP_STATUS_NOT_INSTALLED = 0;
const short APP_STATUS_INSTALLED = 1;
const short APP_STATUS_TRUSTED = 2;
const short APP_STATUS_CERTIFIED = 3;
/**
* Shows the status of the app.
* Can be: APP_STATUS_NOT_INSTALLED, APP_STATUS_INSTALLED,
* APP_STATUS_TRUSTED or APP_STATUS_CERTIFIED.
*/
readonly attribute unsigned short appStatus;
/**
* Returns the app id the principal is in.
* Returns nsIAppsService::NO_APP_ID if this principal isn't part of an app.
*/
readonly attribute unsigned long appId;
};
/**

View File

@ -243,7 +243,8 @@ interface nsIScriptSecurityManager : nsIXPCSecurityManager
/**
* Returns the extended origin for the uri.
* appId can be NO_APP_ID, UNKWOWN_APP_ID or a valid app id.
* appId can be NO_APP_ID or a valid app id. appId should not be
* UNKNOWN_APP_ID.
* inMozBrowser has to be true if the uri is inside a mozbrowser iframe.
*/
AUTF8String getExtendedOrigin(in nsIURI uri, in unsigned long appId,

View File

@ -111,12 +111,6 @@ protected:
class nsPrincipal : public nsBasePrincipal
{
public:
nsPrincipal();
protected:
virtual ~nsPrincipal();
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSISERIALIZABLE
@ -130,16 +124,24 @@ public:
NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval NS_OUTPARAM);
NS_IMETHOD SubsumesIgnoringDomain(nsIPrincipal* other, bool* _retval NS_OUTPARAM);
NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report);
NS_IMETHOD GetExtendedOrigin(nsACString& aExtendedOrigin);
NS_IMETHOD GetAppStatus(PRUint16* aAppStatus);
NS_IMETHOD GetAppId(PRUint32* aAppStatus);
#ifdef DEBUG
virtual void dumpImpl();
#endif
nsPrincipal();
// Either Init() or InitFromPersistent() must be called before
// the principal is in a usable state.
nsresult Init(const nsACString& aCertFingerprint,
const nsACString& aSubjectName,
const nsACString& aPrettyName,
nsISupports* aCert,
nsIURI* aCodebase);
nsIURI* aCodebase,
PRUint32 aAppId,
bool aInMozBrowser);
nsresult InitFromPersistent(const char* aPrefName,
const nsCString& aFingerprint,
const nsCString& aSubjectName,
@ -148,7 +150,9 @@ public:
const char* aDeniedList,
nsISupports* aCert,
bool aIsCert,
bool aTrusted);
bool aTrusted,
PRUint32 aAppId,
bool aInMozBrowser);
virtual void GetScriptLocation(nsACString& aStr) MOZ_OVERRIDE;
void SetURI(nsIURI* aURI);
@ -160,10 +164,20 @@ public:
nsCOMPtr<nsIURI> mDomain;
nsCOMPtr<nsIURI> mCodebase;
PRUint32 mAppId;
bool mInMozBrowser;
// If mCodebaseImmutable is true, mCodebase is non-null and immutable
bool mCodebaseImmutable;
bool mDomainImmutable;
bool mInitialized;
protected:
virtual ~nsPrincipal();
/**
* Returns the app status of the principal based on mAppId and mInMozBrowser.
*/
PRUint16 GetAppStatus();
};
class nsExpandedPrincipal : public nsIExpandedPrincipal, public nsBasePrincipal
@ -188,6 +202,9 @@ public:
NS_IMETHOD Subsumes(nsIPrincipal* other, bool* _retval NS_OUTPARAM);
NS_IMETHOD SubsumesIgnoringDomain(nsIPrincipal* other, bool* _retval NS_OUTPARAM);
NS_IMETHOD CheckMayLoad(nsIURI* uri, bool report);
NS_IMETHOD GetExtendedOrigin(nsACString& aExtendedOrigin);
NS_IMETHOD GetAppStatus(PRUint16* aAppStatus);
NS_IMETHOD GetAppId(PRUint32* aAppStatus);
#ifdef DEBUG
virtual void dumpImpl();
#endif

View File

@ -596,4 +596,13 @@ public:
NS_IMETHOD InitializeNameSet(nsIScriptContext* aScriptContext);
};
namespace mozilla {
void
GetExtendedOrigin(nsIURI* aURI, PRUint32 aAppid,
bool aInMozBrowser,
nsACString& aExtendedOrigin);
} // namespace mozilla
#endif // nsScriptSecurityManager_h__

View File

@ -20,6 +20,7 @@
#include "nsIClassInfoImpl.h"
#include "nsNetCID.h"
#include "nsDOMError.h"
#include "nsIScriptSecurityManager.h"
#include "nsScriptSecurityManager.h"
using namespace mozilla;
@ -314,6 +315,26 @@ nsNullPrincipal::GetCertificate(nsISupports** aCertificate)
return NS_OK;
}
NS_IMETHODIMP
nsNullPrincipal::GetExtendedOrigin(nsACString& aExtendedOrigin)
{
return GetOrigin(getter_Copies(aExtendedOrigin));
}
NS_IMETHODIMP
nsNullPrincipal::GetAppStatus(PRUint16* aAppStatus)
{
*aAppStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
return NS_OK;
}
NS_IMETHODIMP
nsNullPrincipal::GetAppId(PRUint32* aAppId)
{
*aAppId = nsIScriptSecurityManager::NO_APP_ID;
return NS_OK;
}
/**
* nsISerializable implementation
*/

View File

@ -601,7 +601,7 @@ void nsPrincipal::dumpImpl()
{
nsCAutoString str;
GetScriptLocation(str);
fprintf(stderr, "nsPrincipal (%p) = %s\n", this, str.get());
fprintf(stderr, "nsPrincipal (%p) = %s\n", static_cast<void*>(this), str.get());
}
#endif
@ -617,7 +617,9 @@ NS_IMPL_ADDREF_INHERITED(nsPrincipal, nsBasePrincipal)
NS_IMPL_RELEASE_INHERITED(nsPrincipal, nsBasePrincipal)
nsPrincipal::nsPrincipal()
: mCodebaseImmutable(false)
: mAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID)
, mInMozBrowser(false)
, mCodebaseImmutable(false)
, mDomainImmutable(false)
, mInitialized(false)
{ }
@ -630,7 +632,9 @@ nsPrincipal::Init(const nsACString& aCertFingerprint,
const nsACString& aSubjectName,
const nsACString& aPrettyName,
nsISupports* aCert,
nsIURI *aCodebase)
nsIURI *aCodebase,
PRUint32 aAppId,
bool aInMozBrowser)
{
NS_ENSURE_STATE(!mInitialized);
NS_ENSURE_ARG(!aCertFingerprint.IsEmpty() || aCodebase); // better have one of these.
@ -640,6 +644,9 @@ nsPrincipal::Init(const nsACString& aCertFingerprint,
mCodebase = NS_TryToMakeImmutable(aCodebase);
mCodebaseImmutable = URIIsImmutable(mCodebase);
mAppId = aAppId;
mInMozBrowser = aInMozBrowser;
if (aCertFingerprint.IsEmpty())
return NS_OK;
@ -930,8 +937,6 @@ nsPrincipal::SetURI(nsIURI* aURI)
mCodebaseImmutable = URIIsImmutable(mCodebase);
}
NS_IMETHODIMP
nsPrincipal::GetHashValue(PRUint32* aValue)
{
@ -997,7 +1002,9 @@ nsPrincipal::InitFromPersistent(const char* aPrefName,
const char* aDeniedList,
nsISupports* aCert,
bool aIsCert,
bool aTrusted)
bool aTrusted,
PRUint32 aAppId,
bool aInMozBrowser)
{
NS_PRECONDITION(!mCapabilities || mCapabilities->Count() == 0,
"mCapabilities was already initialized?");
@ -1007,6 +1014,9 @@ nsPrincipal::InitFromPersistent(const char* aPrefName,
mInitialized = true;
mAppId = aAppId;
mInMozBrowser = aInMozBrowser;
nsresult rv;
if (aIsCert) {
rv = SetCertificate(aToken, aSubjectName, aPrettyName, aCert);
@ -1052,6 +1062,37 @@ nsPrincipal::InitFromPersistent(const char* aPrefName,
return rv;
}
NS_IMETHODIMP
nsPrincipal::GetExtendedOrigin(nsACString& aExtendedOrigin)
{
MOZ_ASSERT(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
mozilla::GetExtendedOrigin(mCodebase, mAppId, mInMozBrowser, aExtendedOrigin);
return NS_OK;
}
NS_IMETHODIMP
nsPrincipal::GetAppStatus(PRUint16* aAppStatus)
{
MOZ_ASSERT(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
*aAppStatus = GetAppStatus();
return NS_OK;
}
NS_IMETHODIMP
nsPrincipal::GetAppId(PRUint32* aAppId)
{
if (mAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
MOZ_ASSERT(false);
*aAppId = nsIScriptSecurityManager::NO_APP_ID;
return NS_OK;
}
*aAppId = mAppId;
return NS_OK;
}
NS_IMETHODIMP
nsPrincipal::Read(nsIObjectInputStream* aStream)
{
@ -1118,7 +1159,15 @@ nsPrincipal::Read(nsIObjectInputStream* aStream)
return rv;
}
rv = Init(fingerprint, subjectName, prettyName, cert, codebase);
PRUint32 appId;
rv = aStream->Read32(&appId);
NS_ENSURE_SUCCESS(rv, rv);
bool inMozBrowser;
rv = aStream->ReadBoolean(&inMozBrowser);
NS_ENSURE_SUCCESS(rv, rv);
rv = Init(fingerprint, subjectName, prettyName, cert, codebase, appId, inMozBrowser);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIURI> domain;
@ -1214,6 +1263,9 @@ nsPrincipal::Write(nsIObjectOutputStream* aStream)
return rv;
}
aStream->Write32(mAppId);
aStream->WriteBoolean(mInMozBrowser);
rv = aStream->Write8(mTrusted);
if (NS_FAILED(rv)) {
return rv;
@ -1225,6 +1277,18 @@ nsPrincipal::Write(nsIObjectOutputStream* aStream)
return NS_OK;
}
PRUint16
nsPrincipal::GetAppStatus()
{
MOZ_ASSERT(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
// Installed apps have a valid app id (not NO_APP_ID or UNKNOWN_APP_ID)
// and they are not inside a mozbrowser.
return mAppId != nsIScriptSecurityManager::NO_APP_ID &&
mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID && !mInMozBrowser
? nsIPrincipal::APP_STATUS_INSTALLED
: nsIPrincipal::APP_STATUS_NOT_INSTALLED;
}
/************************************************************************************************************************/
@ -1394,6 +1458,24 @@ nsExpandedPrincipal::GetWhiteList(nsTArray<nsCOMPtr<nsIPrincipal> >** aWhiteList
return NS_OK;
}
NS_IMETHODIMP
nsExpandedPrincipal::GetExtendedOrigin(nsACString& aExtendedOrigin)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsExpandedPrincipal::GetAppStatus(PRUint16* aAppStatus)
{
return NS_ERROR_NOT_AVAILABLE;
}
NS_IMETHODIMP
nsExpandedPrincipal::GetAppId(PRUint32* aAppId)
{
return NS_ERROR_NOT_AVAILABLE;
}
void
nsExpandedPrincipal::GetScriptLocation(nsACString& aStr)
{
@ -1408,7 +1490,7 @@ nsExpandedPrincipal::GetScriptLocation(nsACString& aStr)
#ifdef DEBUG
void nsExpandedPrincipal::dumpImpl()
{
fprintf(stderr, "nsExpandedPrincipal (%p)\n", this);
fprintf(stderr, "nsExpandedPrincipal (%p)\n", static_cast<void*>(this));
}
#endif

View File

@ -60,7 +60,6 @@
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/StandardInteger.h"
#include "mozilla/ClearOnShutdown.h"
#include "nsIAppsService.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -1864,7 +1863,8 @@ nsScriptSecurityManager::DoGetCertificatePrincipal(const nsACString& aCertFinger
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = certificate->Init(aCertFingerprint, aSubjectName,
aPrettyName, aCertificate, aURI);
aPrettyName, aCertificate, aURI,
UNKNOWN_APP_ID, false);
NS_ENSURE_SUCCESS(rv, rv);
// Check to see if we already have this principal.
@ -1925,7 +1925,8 @@ nsScriptSecurityManager::DoGetCertificatePrincipal(const nsACString& aCertFinger
subjectName, aPrettyName,
granted, denied,
aCertificate,
true, false);
true, false,
UNKNOWN_APP_ID, false);
if (NS_FAILED(rv))
return rv;
@ -1964,7 +1965,8 @@ nsScriptSecurityManager::CreateCodebasePrincipal(nsIURI* aURI, nsIPrincipal **re
return NS_ERROR_OUT_OF_MEMORY;
nsresult rv = codebase->Init(EmptyCString(), EmptyCString(),
EmptyCString(), nsnull, aURI);
EmptyCString(), nsnull, aURI,
nsIScriptSecurityManager::NO_APP_ID, false);
if (NS_FAILED(rv))
return rv;
@ -2025,7 +2027,9 @@ nsScriptSecurityManager::GetCodebasePrincipal(nsIURI *aURI,
subjectName, EmptyCString(),
granted, denied,
nsnull, false,
isTrusted);
isTrusted,
nsIScriptSecurityManager::NO_APP_ID,
false);
if (NS_FAILED(rv))
return rv;
@ -3494,7 +3498,8 @@ nsScriptSecurityManager::InitPrincipals(PRUint32 aPrefCount, const char** aPrefN
rv = newPrincipal->InitFromPersistent(aPrefNames[c], id, subjectName,
EmptyCString(),
grantedList, deniedList, nsnull,
isCert, isTrusted);
isCert, isTrusted, UNKNOWN_APP_ID,
false);
if (NS_SUCCEEDED(rv))
mPrincipals.Put(newPrincipal, newPrincipal);
}
@ -3552,37 +3557,48 @@ nsScriptSecurityManager::InitPrefs()
return NS_OK;
}
namespace mozilla {
void
GetExtendedOrigin(nsIURI* aURI, PRUint32 aAppId, bool aInMozBrowser,
nsACString& aExtendedOrigin)
{
MOZ_ASSERT(aURI);
MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
if (aAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
aAppId = nsIScriptSecurityManager::NO_APP_ID;
}
nsCAutoString origin;
nsPrincipal::GetOriginForURI(aURI, getter_Copies(origin));
// Fallback.
if (aAppId == nsIScriptSecurityManager::NO_APP_ID && !aInMozBrowser) {
aExtendedOrigin.Assign(origin);
return;
}
// aExtendedOrigin = origin + "@" + aAppId + { 't', 'f' }
aExtendedOrigin.Assign(origin + NS_LITERAL_CSTRING("@"));
aExtendedOrigin.AppendInt(aAppId);
aExtendedOrigin.Append(aInMozBrowser ? NS_LITERAL_CSTRING("t")
: NS_LITERAL_CSTRING("f"));
return;
}
} // namespace mozilla
NS_IMETHODIMP
nsScriptSecurityManager::GetExtendedOrigin(nsIURI* aURI,
PRUint32 aAppId,
bool aInMozBrowser,
nsACString& aExtendedOrigin)
{
MOZ_ASSERT(aURI);
if (aAppId == UNKNOWN_APP_ID) {
aExtendedOrigin.Truncate();
return NS_OK;
}
// Fallback.
if (aAppId == nsIScriptSecurityManager::NO_APP_ID && !aInMozBrowser) {
nsCAutoString origin;
nsPrincipal::GetOriginForURI(aURI, getter_Copies(origin));
aExtendedOrigin.Assign(origin);
return NS_OK;
}
nsCAutoString origin;
nsPrincipal::GetOriginForURI(aURI, getter_Copies(origin));
// aExtendedOrigin = origin + " " + aAppId + " " + int(aInMozBrowser)
aExtendedOrigin.Assign(origin + NS_LITERAL_CSTRING("@"));
aExtendedOrigin.AppendInt(aAppId);
aExtendedOrigin.Append(aInMozBrowser ? NS_LITERAL_CSTRING("t")
: NS_LITERAL_CSTRING("f"));
MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
mozilla::GetExtendedOrigin(aURI, aAppId, aInMozBrowser, aExtendedOrigin);
return NS_OK;
}

View File

@ -16,6 +16,7 @@
#include "nsCRT.h"
#include "nsString.h"
#include "nsIClassInfoImpl.h"
#include "nsIScriptSecurityManager.h"
NS_IMPL_CLASSINFO(nsSystemPrincipal, NULL,
nsIClassInfo::SINGLETON | nsIClassInfo::MAIN_THREAD_ONLY,
@ -237,6 +238,25 @@ nsSystemPrincipal::SetSecurityPolicy(void* aSecurityPolicy)
return NS_OK;
}
NS_IMETHODIMP
nsSystemPrincipal::GetExtendedOrigin(nsACString& aExtendedOrigin)
{
return GetOrigin(getter_Copies(aExtendedOrigin));
}
NS_IMETHODIMP
nsSystemPrincipal::GetAppStatus(PRUint16* aAppStatus)
{
*aAppStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
return NS_OK;
}
NS_IMETHODIMP
nsSystemPrincipal::GetAppId(PRUint32* aAppId)
{
*aAppId = nsIScriptSecurityManager::NO_APP_ID;
return NS_OK;
}
//////////////////////////////////////////
// Methods implementing nsISerializable //

View File

@ -20,71 +20,75 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=758258
/** Test for Bug 758258 **/
var Ci = Components.interfaces;
SimpleTest.waitForExplicitFinish();
var gData = [
{
app: "http://example.org/manifest.webapp",
origin: "http://example.org",
src: "http://example.org/",
},
{
app: "https://example.com:443/manifest.webapp",
origin: "https://example.com",
src: "https://example.com/",
},
{
app: "http://test1.example.org/manifest.webapp",
origin: "http://test1.example.org",
src: "http://test1.example.org/",
},
{
app: "http://test1.example.org:8000/manifest.webapp",
origin: "http://test1.example.org:8000",
src: "http://test1.example.org:8000/",
},
{
app: "http://sub1.test1.example.org/manifest.webapp",
origin: "http://sub1.test1.example.org",
src: "http://sub1.test1.example.org/",
},
{
app: "http://example.org/foo/manifest.webapp",
origin: "http://example.org",
src: "http://example.org/",
},
{
app: "http://example.org/bar/manifest.webapp",
origin: "http://example.org",
src: "http://example.org/",
},
{
browser: true,
origin: "http://example.org",
src: "http://example.org/",
},
{
origin: "http://example.org",
src: "http://example.org/",
},
{
app: "http://example.org/wedonthaveanyappinthatdirectory/manifest.webapp",
origin: "http://example.org",
src: "http://example.org/",
},
/*
{
app: "http://example.org/manifest.webapp",
src: "data:text/html,foobar",
test: [ "todo-src" ],
},
{
app: "http://example.org/manifest.webapp",
origin: "data:text/html,foobar",
test: [ "todo-origin" ],
src: "data:text/html,foobar2",
test: [ "todo-src" ],
},
*/
{
src: "file:///",
},
{
src: "file:///tmp",
},
{
app: "http://example.org/manifest.webapp",
origin: "data:text/html,foobar2",
test: [ "todo-origin" ],
},
{
origin: "file:///",
},
{
origin: "file:///tmp",
src: "file:///",
},
{
app: "http://example.org/manifest.webapp",
origin: "file:///",
},
{
app: "http://example.org/manifest.webapp",
origin: "file:///tmp",
src: "file:///tmp",
},
];
@ -100,15 +104,15 @@ function checkPrincipalForIFrame(aFrame, data) {
data.test = [];
}
/*
if (data.test.indexOf('todo-origin') == -1) {
var origin = data.origin;
if (navigator.platform.indexOf("Mac") != 1) {
origin = origin.replace("file:///", "file:///private/");
}
is(principal.origin, origin, 'the correct URL should have been loaded');
}
*/
is(principal.URI.spec, data.src,
'the correct URL should have been loaded');
is(principal.appStatus, Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED,
'principal is not part of an installed app');
is(principal.extendedOrigin, principal.origin,
"extendedOrigin returns the origin for the moment");
is(principal.appId, Ci.nsIScriptSecurityManager.NO_APP_ID,
"appId is always NO_APP_ID for the moment");
checkedCount++;
if (checkedCount == checksTodo) {
@ -116,12 +120,12 @@ function checkPrincipalForIFrame(aFrame, data) {
}
}
is('appStatus' in document.nodePrincipal, false,
'appStatus should not be present in nsIPrincipal');
is('extendedOrigin' in document.nodePrincipal, false,
'extendedOrigin should not be present in nsIPrincipal');
is('appId' in document.nodePrincipal, false,
'appId should not be present in nsIPrincipal');
is('appStatus' in document.nodePrincipal, true,
'appStatus should be present in nsIPrincipal');
is('extendedOrigin' in document.nodePrincipal, true,
'extendedOrigin should be present in nsIPrincipal');
is('appId' in document.nodePrincipal, true,
'appId should be present in nsIPrincipal');
gData.forEach(function(data) {
var iframe = document.createElement('iframe');
@ -136,7 +140,7 @@ gData.forEach(function(data) {
iframe.setAttribute('mozbrowser', '');
}
iframe.src = data.origin;
iframe.src = data.src;
iframe.addEventListener('load', iframe.checkPrincipal.bind(iframe));