Bug 734891 - part 2: Adding ExpandedPrincipal support

This commit is contained in:
Gabor Krizsanits 2012-06-09 15:19:26 -07:00
Родитель f6671a8565
Коммит 277f347d94
4 изменённых файлов: 281 добавлений и 1 удалений

Просмотреть файл

@ -10,6 +10,8 @@
%{C++
struct JSContext;
struct JSPrincipals;
#include "nsCOMPtr.h"
#include "nsTArray.h"
%}
interface nsIURI;
@ -17,6 +19,7 @@ interface nsIContentSecurityPolicy;
[ptr] native JSContext(JSContext);
[ptr] native JSPrincipals(JSPrincipals);
[ptr] native PrincipalArray(nsTArray<nsCOMPtr<nsIPrincipal> >);
[scriptable, uuid(42ba6a38-d619-49ab-8248-3d247e959d5e)]
interface nsIPrincipal : nsISerializable
@ -210,3 +213,25 @@ interface nsIPrincipal : nsISerializable
*/
[noscript] attribute nsIContentSecurityPolicy csp;
};
/**
* If nsSystemPrincipal is too risky to use, but we want a principal to access
* more than one origin, nsExpandedPrincipals letting us define an array of
* principals it subsumes. So script with an nsExpandedPrincipals will gain
* same origin access when at least one of its principals it contains gained
* sameorigin acccess. An nsExpandedPrincipal will be subsumed by the system
* principal, and by another nsExpandedPrincipal that has all its principals.
* It is added for jetpack content-scripts to let them interact with the
* content and a well defined set of other domains, without the risk of
* leaking out a system principal to the content. See: Bug 734891
*/
[uuid(f3e177Df-6a5e-489f-80a7-2dd1481471d8)]
interface nsIExpandedPrincipal : nsISupports
{
/**
* An array of principals that the expanded principal subsumes.
* Note: this list is not reference counted, it is shared, so
* should not be changed and should only be used ephemerally.
*/
[notxpcom] readonly attribute PrincipalArray whiteList;
};

Просмотреть файл

@ -16,6 +16,7 @@
class nsIObjectInputStream;
class nsIObjectOutputStream;
class DomainPolicy;
class nsBasePrincipal : public nsJSPrincipals
{
@ -160,6 +161,37 @@ public:
bool mInitialized;
};
class nsExpandedPrincipal : public nsIExpandedPrincipal, public nsBasePrincipal
{
public:
nsExpandedPrincipal(nsTArray< nsCOMPtr<nsIPrincipal> > &aWhiteList);
protected:
virtual ~nsExpandedPrincipal();
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIEXPANDEDPRINCIPAL
NS_DECL_NSISERIALIZABLE
NS_IMETHOD Equals(nsIPrincipal* other, bool* _retval NS_OUTPARAM);
NS_IMETHOD EqualsIgnoringDomain(nsIPrincipal* other, bool* _retval NS_OUTPARAM);
NS_IMETHOD GetHashValue(PRUint32* aHashValue);
NS_IMETHOD GetURI(nsIURI** aURI);
NS_IMETHOD GetDomain(nsIURI** aDomain);
NS_IMETHOD SetDomain(nsIURI* aDomain);
NS_IMETHOD GetOrigin(char** aOrigin);
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);
#ifdef DEBUG
virtual void dumpImpl();
#endif
virtual void GetScriptLocation(nsACString &aStr) MOZ_OVERRIDE;
private:
nsTArray< nsCOMPtr<nsIPrincipal> > mPrincipals;
};
#define NS_PRINCIPAL_CLASSNAME "principal"
#define NS_PRINCIPAL_CONTRACTID "@mozilla.org/principal;1"
@ -167,5 +199,10 @@ public:
{ 0x36102b6b, 0x7b62, 0x451a, \
{ 0xa1, 0xc8, 0xa0, 0xd4, 0x56, 0xc9, 0x2d, 0xc5 }}
#define NS_EXPANDEDPRINCIPAL_CLASSNAME "expandedprincipal"
#define NS_EXPANDEDPRINCIPAL_CONTRACTID "@mozilla.org/expandedprincipal;1"
#define NS_EXPANDEDPRINCIPAL_CID \
{ 0xb33a3807, 0xb76c, 0x44e5, \
{ 0xb9, 0x9d, 0x95, 0x7e, 0xe9, 0xba, 0x6e, 0x39 }}
#endif // nsPrincipal_h__

Просмотреть файл

@ -1202,3 +1202,206 @@ nsPrincipal::Write(nsIObjectOutputStream* aStream)
return NS_OK;
}
/************************************************************************************************************************/
static const char EXPANDED_PRINCIPAL_SPEC[] = "[Expanded Principal]";
NS_IMPL_CLASSINFO(nsExpandedPrincipal, NULL, nsIClassInfo::MAIN_THREAD_ONLY,
NS_EXPANDEDPRINCIPAL_CID)
NS_IMPL_QUERY_INTERFACE2_CI(nsExpandedPrincipal,
nsIPrincipal,
nsIExpandedPrincipal)
NS_IMPL_CI_INTERFACE_GETTER2(nsExpandedPrincipal,
nsIPrincipal,
nsIExpandedPrincipal)
NS_IMPL_ADDREF_INHERITED(nsExpandedPrincipal, nsBasePrincipal);
NS_IMPL_RELEASE_INHERITED(nsExpandedPrincipal, nsBasePrincipal);
nsExpandedPrincipal::nsExpandedPrincipal(nsTArray<nsCOMPtr <nsIPrincipal> > &aWhiteList)
{
mPrincipals.AppendElements(aWhiteList);
}
nsExpandedPrincipal::~nsExpandedPrincipal()
{ }
NS_IMETHODIMP
nsExpandedPrincipal::GetDomain(nsIURI** aDomain)
{
*aDomain = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsExpandedPrincipal::SetDomain(nsIURI* aDomain)
{
return NS_OK;
}
NS_IMETHODIMP
nsExpandedPrincipal::GetOrigin(char** aOrigin)
{
*aOrigin = ToNewCString(NS_LITERAL_CSTRING(EXPANDED_PRINCIPAL_SPEC));
return *aOrigin ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
}
typedef nsresult (NS_STDCALL nsIPrincipal::*nsIPrincipalMemFn)(nsIPrincipal* aOther,
bool* aResult);
#define CALL_MEMBER_FUNCTION(THIS,MEM_FN) ((THIS)->*(MEM_FN))
// nsExpandedPrincipal::Equals and nsExpandedPrincipal::EqualsIgnoringDomain
// shares the same logic. The difference only that Equals requires 'this'
// and 'aOther' to Subsume each other while EqualsIgnoringDomain requires
// bidirectional SubsumesIgnoringDomain.
static nsresult
Equals(nsExpandedPrincipal* aThis, nsIPrincipalMemFn aFn, nsIPrincipal* aOther,
bool* aResult)
{
// If (and only if) 'aThis' and 'aOther' both Subsume/SubsumesIgnoringDomain
// each other, then they are Equal.
*aResult = false;
// Calling the corresponding subsume function on this (aFn).
nsresult rv = CALL_MEMBER_FUNCTION(aThis, aFn)(aOther, aResult);
NS_ENSURE_SUCCESS(rv, rv);
if (!*aResult)
return NS_OK;
// Calling the corresponding subsume function on aOther (aFn).
rv = CALL_MEMBER_FUNCTION(aOther, aFn)(aThis, aResult);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsExpandedPrincipal::Equals(nsIPrincipal* aOther, bool* aResult)
{
return ::Equals(this, &nsIPrincipal::Subsumes, aOther, aResult);
}
NS_IMETHODIMP
nsExpandedPrincipal::EqualsIgnoringDomain(nsIPrincipal* aOther, bool* aResult)
{
return ::Equals(this, &nsIPrincipal::SubsumesIgnoringDomain, aOther, aResult);
}
// nsExpandedPrincipal::Subsumes and nsExpandedPrincipal::SubsumesIgnoringDomain
// shares the same logic. The difference only that Subsumes calls are replaced
//with SubsumesIgnoringDomain calls in the second case.
static nsresult
Subsumes(nsExpandedPrincipal* aThis, nsIPrincipalMemFn aFn, nsIPrincipal* aOther,
bool* aResult)
{
nsresult rv;
nsCOMPtr<nsIExpandedPrincipal> expanded = do_QueryInterface(aOther);
if (expanded) {
// If aOther is an ExpandedPrincipal too, check if all of its
// principals are subsumed.
nsTArray< nsCOMPtr<nsIPrincipal> >* otherList;
expanded->GetWhiteList(&otherList);
for (uint32_t i = 0; i < otherList->Length(); ++i){
rv = CALL_MEMBER_FUNCTION(aThis, aFn)((*otherList)[i], aResult);
NS_ENSURE_SUCCESS(rv, rv);
if (!*aResult) {
// If we don't subsume at least one principal of aOther, return false.
return NS_OK;
}
}
} else {
// For a regular aOther, one of our principals must subsume it.
nsTArray< nsCOMPtr<nsIPrincipal> >* list;
aThis->GetWhiteList(&list);
for (uint32_t i = 0; i < list->Length(); ++i){
rv = CALL_MEMBER_FUNCTION((*list)[i], aFn)(aOther, aResult);
NS_ENSURE_SUCCESS(rv, rv);
if (*aResult) {
// If one of our principal subsumes it, return true.
return NS_OK;
}
}
}
return NS_OK;
}
#undef CALL_MEMBER_FUNCTION
NS_IMETHODIMP
nsExpandedPrincipal::Subsumes(nsIPrincipal* aOther, bool* aResult)
{
return ::Subsumes(this, &nsIPrincipal::Subsumes, aOther, aResult);
}
NS_IMETHODIMP
nsExpandedPrincipal::SubsumesIgnoringDomain(nsIPrincipal* aOther, bool* aResult)
{
return ::Subsumes(this, &nsIPrincipal::SubsumesIgnoringDomain, aOther, aResult);
}
NS_IMETHODIMP
nsExpandedPrincipal::CheckMayLoad(nsIURI* uri, bool aReport)
{
nsresult rv;
for (uint32_t i = 0; i < mPrincipals.Length(); ++i){
rv = mPrincipals[i]->CheckMayLoad(uri, aReport);
if (NS_SUCCEEDED(rv))
return rv;
}
return NS_ERROR_DOM_BAD_URI;
}
NS_IMETHODIMP
nsExpandedPrincipal::GetHashValue(PRUint32* result)
{
MOZ_NOT_REACHED("extended principal should never be used as key in a hash map");
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsExpandedPrincipal::GetURI(nsIURI** aURI)
{
*aURI = nsnull;
return NS_OK;
}
NS_IMETHODIMP
nsExpandedPrincipal::GetWhiteList(nsTArray<nsCOMPtr<nsIPrincipal> >** aWhiteList)
{
*aWhiteList = &mPrincipals;
return NS_OK;
}
void
nsExpandedPrincipal::GetScriptLocation(nsACString& aStr)
{
if (mCert) {
aStr.Assign(mCert->fingerprint);
} else {
// Is that a good idea to list it's principals?
aStr.Assign(EXPANDED_PRINCIPAL_SPEC);
}
}
#ifdef DEBUG
void nsExpandedPrincipal::dumpImpl()
{
fprintf(stderr, "nsExpandedPrincipal (%p)\n", this);
}
#endif
//////////////////////////////////////////
// Methods implementing nsISerializable //
//////////////////////////////////////////
NS_IMETHODIMP
nsExpandedPrincipal::Read(nsIObjectInputStream* aStream)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP
nsExpandedPrincipal::Write(nsIObjectOutputStream* aStream)
{
return NS_ERROR_NOT_IMPLEMENTED;
}

Просмотреть файл

@ -1344,7 +1344,22 @@ nsScriptSecurityManager::CheckLoadURIWithPrincipal(nsIPrincipal* aPrincipal,
nsCOMPtr<nsIURI> sourceURI;
aPrincipal->GetURI(getter_AddRefs(sourceURI));
if (!sourceURI) {
NS_ERROR("Non-system principals passed to CheckLoadURIWithPrincipal "
nsCOMPtr<nsIExpandedPrincipal> expanded = do_QueryInterface(aPrincipal);
if (expanded) {
nsTArray< nsCOMPtr<nsIPrincipal> > *whiteList;
expanded->GetWhiteList(&whiteList);
for (uint32_t i = 0; i < whiteList->Length(); ++i) {
nsresult rv = CheckLoadURIWithPrincipal((*whiteList)[i],
aTargetURI,
aFlags);
if (NS_SUCCEEDED(rv)) {
// Allow access if it succeeded with one of the white listed principals
return NS_OK;
}
}
return NS_OK;
}
NS_ERROR("Non-system principals or expanded principal passed to CheckLoadURIWithPrincipal "
"must have a URI!");
return NS_ERROR_UNEXPECTED;
}