Override same origin check for public services listed in the master service list. b=203371, r=darin@netscape.com sr=jst@netscape.com

This commit is contained in:
harishd%netscape.com 2003-07-01 18:51:59 +00:00
Родитель 7146549efc
Коммит da49627bbe
6 изменённых файлов: 811 добавлений и 300 удалений

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

@ -53,10 +53,12 @@ REQUIRES = xpcom \
necko \
intl \
xmlextras \
pref \
$(NULL)
CPPSRCS = \
nsWebScriptsAccess.cpp \
nsWSAUtils.cpp \
$(NULL)
LOCAL_INCLUDES = \

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

@ -0,0 +1,330 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the web scripts access security code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2003
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Harish Dhurvasula <harishd@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsWSAUtils.h"
#include "nsReadableUtils.h"
#include "nsIStringBundle.h"
#include "nsIConsoleService.h"
#include "nsIServiceManager.h"
#include "nsIDNSService.h"
#include "nsIRequest.h"
#include "nsEventQueueUtils.h"
#include "nsAutoPtr.h"
static const char kSecurityProperties[] =
"chrome://communicator/locale/webservices/security.properties";
static NS_DEFINE_CID(kDNSServiceCID, NS_DNSSERVICE_CID);
static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
class nsDNSListener : public nsIDNSListener
{
public:
nsDNSListener();
virtual ~nsDNSListener();
NS_DECL_ISUPPORTS
NS_DECL_NSIDNSLISTENER
nsCString mOfficialHostName;
PRBool mLookupFinished;
};
#ifdef DEBUG
struct TestStruct {
const char* lhs; // string that contains the wild char(s).
const char* rhs; // string that is compared against lhs.
PRBool equal; // set to true if lhs and rhs are expected
// to be equal else set false;
};
static
const TestStruct kStrings[] = {
{ "f*o*bar", "foobar", PR_TRUE },
{ "foo*bar", "foofbar", PR_TRUE },
{ "*foo*bar", "ffoofoobbarbarbar", PR_TRUE },
{ "*foo*bar*barbar", "ffoofoobbarbarbar", PR_TRUE },
{ "http://*.*.*/*", "http://www.mozilla.org/", PR_TRUE},
{ "http://*/*", "http://www.mozilla.org/", PR_TRUE},
{ "http://*.mozilla.org/*/*", "http://www.mozilla.org/Projects/", PR_TRUE},
{ "http://www.m*zi*la.org/*", "http://www.mozilla.org/", PR_TRUE },
{ "http://www.mozilla.org/*.html", "http://www.mozilla.org/owners.html", PR_TRUE },
{ "http://www.mozilla.org/*.htm*", "http://www.mozilla.org/owners.html", PR_TRUE },
{ "http://www.mozilla.org/*rs.htm*", "http://www.mozilla.org/ownres.html", PR_FALSE },
{ "http://www.mozilla.org/a*c.html", "http://www.mozilla.org/abcd.html", PR_FALSE },
{ "https://www.mozilla.org/*", "http://www.mozilla.org/abcd.html", PR_FALSE },
};
void
nsWSAUtils::VerifyIsEqual()
{
static PRUint32 size = NS_ARRAY_LENGTH(kStrings);
PRUint32 i;
for (i = 0; i < size; ++i) {
if (IsEqual(NS_ConvertUTF8toUCS2(kStrings[i].lhs),
NS_ConvertUTF8toUCS2(kStrings[i].rhs))
!= kStrings[i].equal) {
const char* equal =
kStrings[i].equal ? "equivalent" :
"not equivalent";
printf("\nTest Failed: %s is %s to %s.\n",
kStrings[i].lhs, equal, kStrings[i].rhs);
}
}
}
#endif
/**
* This method compares two strings where the lhs string value may contain
* asterisk. Therefore, an lhs with a value of "he*o" should be equal to a rhs
* value of "hello" or "hero" etc.. These strings are compared as follows:
* 1) Characters before the first asterisk are compared from left to right.
* Thus if the lhs string did not contain an asterisk then we just do
* a simple string comparison.
* 2) Match a pattern, found between asterisk. That is, if lhs and rhs were
* "h*ll*" and "hello" respectively, then compare the pattern "ll".
* 3) Characters after the last asterisk are compared from right to left.
* Thus, "*lo" == "hello" and != "blow"
*/
PRBool
nsWSAUtils::IsEqual(const nsAString& aLhs, const nsAString& aRhs)
{
nsAString::const_iterator lhs_begin, lhs_end;
nsAString::const_iterator rhs_begin, rhs_end;
aLhs.BeginReading(lhs_begin);
aLhs.EndReading(lhs_end);
aRhs.BeginReading(rhs_begin);
aRhs.EndReading(rhs_end);
PRBool pattern_before_asterisk = PR_TRUE;
nsAString::const_iterator curr_posn = lhs_begin;
while (curr_posn != lhs_end) {
if (*lhs_begin == '*') {
pattern_before_asterisk = PR_FALSE;
++lhs_begin; // Do this to not include '*' when pattern matching.
}
else if (pattern_before_asterisk) {
// Match character by character to see if lhs and rhs are identical
if (*curr_posn != *rhs_begin) {
return PR_FALSE;
}
++lhs_begin;
++curr_posn;
++rhs_begin;
if (rhs_begin == rhs_end &&
curr_posn == lhs_end) {
return PR_TRUE; // lhs and rhs matched perfectly
}
}
else if (++curr_posn == lhs_end) {
if (curr_posn != lhs_begin) {
// Here we're matching the last few characters to make sure
// that lhs is actually equal to rhs. Ex. "a*c" != "abcd"
// and "*xabcd" != "abcd".
PRBool done = PR_FALSE;
for (;;) {
if (--curr_posn == lhs_begin)
done = PR_TRUE;
if (rhs_end == rhs_begin)
return PR_FALSE;
if (*(--rhs_end) != *curr_posn)
return PR_FALSE;
if (done)
return PR_TRUE;
}
}
// No discrepency between lhs and rhs
return PR_TRUE;
}
else if (*curr_posn == '*') {
// Matching pattern between asterisks. That is, in "h*ll*" we
// check to see if "ll" exists in the rhs string.
const nsAString& pattern = Substring(lhs_begin, curr_posn);
nsAString::const_iterator tmp_end = rhs_end;
if (!FindInReadable(pattern, rhs_begin, rhs_end)) {
return PR_FALSE;
}
rhs_begin = rhs_end;
rhs_end = tmp_end;
lhs_begin = curr_posn;
}
}
return PR_FALSE;
}
nsresult
nsWSAUtils::ReportError(const PRUnichar* aMessageID,
const PRUnichar** aInputs,
const PRInt32 aLength)
{
nsCOMPtr<nsIStringBundleService> bundleService
= do_GetService(NS_STRINGBUNDLE_CONTRACTID);
NS_ENSURE_TRUE(bundleService, NS_OK); // intentionally returning NS_OK;
nsCOMPtr<nsIStringBundle> bundle;
bundleService->CreateBundle(kSecurityProperties, getter_AddRefs(bundle));
NS_ENSURE_TRUE(bundle, NS_OK);
nsXPIDLString message;
bundle->FormatStringFromName(aMessageID, aInputs, aLength,
getter_Copies(message));
nsCOMPtr<nsIConsoleService> consoleService =
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
NS_ENSURE_TRUE(consoleService, NS_OK); // intentionally returning NS_OK;
return consoleService->LogStringMessage(message.get());
}
nsresult
nsWSAUtils::GetOfficialHostName(nsIURI* aServiceURI,
nsACString& aResult)
{
NS_ASSERTION(aServiceURI, "Cannot get FQDN for a null URI!");
if (!aServiceURI)
return NS_ERROR_NULL_POINTER;
nsresult rv;
nsCOMPtr<nsIDNSService> dns(do_GetService(kDNSServiceCID, &rv));
if (NS_FAILED(rv))
return rv;
nsXPIDLCString host;
aServiceURI->GetHost(host);
nsRefPtr<nsDNSListener> listener = new nsDNSListener();
NS_ENSURE_TRUE(listener, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<nsIRequest> dummy;
rv = dns->Lookup(host, listener, nsnull, getter_AddRefs(dummy));
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIEventQueueService> eventQService =
do_GetService(kEventQueueServiceCID, &rv);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIEventQueue> eventQ;
rv = eventQService->PushThreadEventQueue(getter_AddRefs(eventQ));
if (NS_FAILED(rv))
return rv;
while (!listener->mLookupFinished)
eventQ->ProcessPendingEvents();
eventQService->PopThreadEventQueue(eventQ);
aResult.Assign(listener->mOfficialHostName);
return NS_OK;
}
static void* PR_CALLBACK
EventHandler(PLEvent *aEvent)
{
nsDNSListener* listener = (nsDNSListener*)PL_GetEventOwner(aEvent);
if (listener)
listener->mLookupFinished = PR_TRUE;
return 0;
}
static void PR_CALLBACK
DestroyHandler(PLEvent *aEvent)
{
delete aEvent;
}
NS_IMPL_THREADSAFE_ISUPPORTS1(nsDNSListener,
nsIDNSListener);
nsDNSListener::nsDNSListener()
: mLookupFinished(PR_FALSE)
{
}
nsDNSListener::~nsDNSListener()
{
}
NS_IMETHODIMP
nsDNSListener::OnStartLookup(nsISupports* aContext, const char* aHost)
{
return NS_OK;
}
NS_IMETHODIMP
nsDNSListener::OnFound(nsISupports* aContext,
const char* aHost,
nsHostEnt* aHostEnt)
{
if (aHostEnt)
mOfficialHostName.Assign(aHostEnt->hostEnt.h_name);
return NS_OK;
}
NS_IMETHODIMP
nsDNSListener::OnStopLookup(nsISupports* aContext,
const char* aHost,
nsresult aStatus)
{
// Post an event to the UI thread's event queue to cause
// ProcessPendingEvents to run.
nsCOMPtr<nsIEventQueue> uiEventQ;
nsresult rv = NS_GetMainEventQ(getter_AddRefs(uiEventQ));
if (uiEventQ) {
PLEvent* event = new PLEvent();
NS_ENSURE_TRUE(event, NS_ERROR_OUT_OF_MEMORY);
PL_InitEvent(event, this, EventHandler, DestroyHandler);
rv = uiEventQ->PostEvent(event);
if (NS_FAILED(rv))
PL_DestroyEvent(event);
}
return rv;
}

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

@ -0,0 +1,65 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is the web scripts access security code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 2003
* the Initial Developer. All Rights Reserved.
*
* Contributor(s): Harish Dhurvasula <harishd@netscape.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsWSAUtils_h__
#define nsWSAUtils_h__
#include "nsIDNSListener.h"
#include "nsIEventQueueService.h"
#include "nsIURI.h"
#include "nsCOMPtr.h"
#include "nsString.h"
class nsWSAUtils
{
public:
static PRBool IsEqual(const nsAString& aLhs, const nsAString& aRhs);
static nsresult ReportError(const PRUnichar* aMessageID,
const PRUnichar** aInputs,
const PRInt32 aLength);
static nsresult GetOfficialHostName(nsIURI* aURI, nsACString& aResult);
#ifdef DEBUG
static void VerifyIsEqual();
#endif
private:
// Use the |static| methods |only|
nsWSAUtils() {}
~nsWSAUtils() {}
};
#endif

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

@ -43,23 +43,31 @@
#include "nsIDOMNodeList.h"
#include "nsIDOMAttr.h"
#include "nsIDOMNamedNodeMap.h"
#include "nsComponentManagerUtils.h"
#include "nsIServiceManagerUtils.h"
#include "nsICodebasePrincipal.h"
#include "nsIURL.h"
#include "nsReadableUtils.h"
#include "nsIHttpChannel.h"
#include "nsNetUtil.h"
#include "nsIStringBundle.h"
#include "nsIConsoleService.h"
#include "nsIXPConnect.h"
#include "jsapi.h"
#define WSA_GRANT_ACCESS_TO_ALL (1 << 0)
#define WSA_FILE_NOT_FOUND (1 << 1)
#define WSA_FILE_DELEGATED (1 << 2)
#include "nsISOAPCall.h"
#include "nsISOAPEncoding.h"
#include "nsISOAPResponse.h"
#include "nsISOAPFault.h"
#include "nsISOAPParameter.h"
#include "nsISOAPBlock.h"
#include "nsIVariant.h"
#include "nsIPrefService.h"
#include "nsIPrefBranchInternal.h"
#include "nsIPref.h"
#include "nsIJSContextStack.h"
#define SECURITY_PROPERTIES "chrome://communicator/locale/webservices/security.properties"
#define WSA_GRANT_ACCESS_TO_ALL (1 << 0)
#define WSA_FILE_NOT_FOUND (1 << 1)
#define WSA_FILE_DELEGATED (1 << 2)
#define SERVICE_LISTED_PUBLIC (1 << 3)
#define HAS_MASTER_SERVICE_DECISION (1 << 4)
NS_NAMED_LITERAL_STRING(kNamespace2002, "http://www.mozilla.org/2002/soap/security");
@ -75,132 +83,8 @@ NS_NAMED_LITERAL_STRING(kFromAttr, "from");
// Default attribute value
NS_NAMED_LITERAL_STRING(kAny, "any");
/**
* This method compares two strings where the lhs string value may contain
* asterisk. Therefore, an lhs with a value of "he*o" should be equal to a rhs
* value of "hello" or "hero" etc.. These strings are compared as follows:
* 1) Characters before the first asterisk are compared from left to right.
* Thus if the lhs string did not contain an asterisk then we just do
* a simple string comparison.
* 2) Match a pattern, found between asterisk. That is, if lhs and rhs were
* "h*ll*" and "hello" respectively, then compare the pattern "ll".
* 3) Characters after the last asterisk are compared from right to left.
* Thus, "*lo" == "hello" and != "blow"
*/
static PRBool
IsEqual(const nsAString& aLhs, const nsAString& aRhs)
{
nsAString::const_iterator lhs_begin, lhs_end;
nsAString::const_iterator rhs_begin, rhs_end;
aLhs.BeginReading(lhs_begin);
aLhs.EndReading(lhs_end);
aRhs.BeginReading(rhs_begin);
aRhs.EndReading(rhs_end);
PRBool pattern_before_asterisk = PR_TRUE;
nsAString::const_iterator curr_posn = lhs_begin;
while (curr_posn != lhs_end) {
if (*lhs_begin == '*') {
pattern_before_asterisk = PR_FALSE;
++lhs_begin; // Do this to not include '*' when pattern matching.
}
else if (pattern_before_asterisk) {
// Match character by character to see if lhs and rhs are identical
if (*curr_posn != *rhs_begin) {
return PR_FALSE;
}
++lhs_begin;
++curr_posn;
++rhs_begin;
if (rhs_begin == rhs_end &&
curr_posn == lhs_end) {
return PR_TRUE; // lhs and rhs matched perfectly
}
}
else if (++curr_posn == lhs_end) {
if (curr_posn != lhs_begin) {
// Here we're matching the last few characters to make sure
// that lhs is actually equal to rhs. Ex. "a*c" != "abcd"
// and "*xabcd" != "abcd".
PRBool done = PR_FALSE;
for (;;) {
if (--curr_posn == lhs_begin)
done = PR_TRUE;
if (rhs_end == rhs_begin)
return PR_FALSE;
if (*(--rhs_end) != *curr_posn)
return PR_FALSE;
if (done)
return PR_TRUE;
}
}
// No discrepency between lhs and rhs
return PR_TRUE;
}
else if (*curr_posn == '*') {
// Matching pattern between asterisks. That is, in "h*ll*" we
// check to see if "ll" exists in the rhs string.
const nsAString& pattern = Substring(lhs_begin, curr_posn);
nsAString::const_iterator tmp_end = rhs_end;
if (!FindInReadable(pattern, rhs_begin, rhs_end)) {
return PR_FALSE;
}
rhs_begin = rhs_end;
rhs_end = tmp_end;
lhs_begin = curr_posn;
}
}
return PR_FALSE;
}
#ifdef DEBUG
struct TestStruct {
const char* lhs; // string that contains the wild char(s).
const char* rhs; // string that is compared against lhs.
PRBool equal; // set to true if lhs and rhs are expected
// to be equal else set false;
};
static
const TestStruct kStrings[] = {
{ "f*o*bar", "foobar", PR_TRUE },
{ "foo*bar", "foofbar", PR_TRUE },
{ "*foo*bar", "ffoofoobbarbarbar", PR_TRUE },
{ "*foo*bar*barbar", "ffoofoobbarbarbar", PR_TRUE },
{ "http://*.*.*/*", "http://www.mozilla.org/", PR_TRUE},
{ "http://*/*", "http://www.mozilla.org/", PR_TRUE},
{ "http://*.mozilla.org/*/*", "http://www.mozilla.org/Projects/", PR_TRUE},
{ "http://www.m*zi*la.org/*", "http://www.mozilla.org/", PR_TRUE },
{ "http://www.mozilla.org/*.html", "http://www.mozilla.org/owners.html", PR_TRUE },
{ "http://www.mozilla.org/*.htm*", "http://www.mozilla.org/owners.html", PR_TRUE },
{ "http://www.mozilla.org/*rs.htm*", "http://www.mozilla.org/ownres.html", PR_FALSE },
{ "http://www.mozilla.org/a*c.html", "http://www.mozilla.org/abcd.html", PR_FALSE },
{ "https://www.mozilla.org/*", "http://www.mozilla.org/abcd.html", PR_FALSE },
};
static
void VerifyIsEqual()
{
static PRUint32 size = sizeof(kStrings)/sizeof(kStrings[0]);
PRUint32 i;
for (i = 0; i < size; ++i) {
if (IsEqual(NS_ConvertUTF8toUCS2(kStrings[i].lhs),
NS_ConvertUTF8toUCS2(kStrings[i].rhs))
!= kStrings[i].equal) {
const char* equal =
kStrings[i].equal ? "equivalent" :
"not equivalent";
printf("\nTest Failed: %s is %s to %s.\n",
kStrings[i].lhs, equal, kStrings[i].rhs);
}
}
}
#endif
// Method name. Note: This method should be implemented by master services.
NS_NAMED_LITERAL_STRING(kIsServicePublic, "isServicePublic");
static PRBool PR_CALLBACK
FreeEntries(nsHashKey *aKey, void *aData, void* aClosure)
@ -212,10 +96,10 @@ FreeEntries(nsHashKey *aKey, void *aData, void* aClosure)
NS_IMPL_ISUPPORTS1(nsWebScriptsAccess,
nsIWebScriptsAccessService)
nsWebScriptsAccess::nsWebScriptsAccess()
{
NS_INIT_ISUPPORTS();
}
nsWebScriptsAccess::~nsWebScriptsAccess()
@ -243,31 +127,6 @@ nsWebScriptsAccess::CanAccess(nsIURI* aTransportURI,
if (NS_FAILED(rv) || *aAccessGranted)
return rv;
rv = mSecurityManager->CheckSameOrigin(0, aTransportURI);
if (NS_SUCCEEDED(rv)) {
// script security manager has granted access
*aAccessGranted = PR_TRUE;
return rv;
}
else {
// Script security manager has denied access and has set an
// exception. Clear the exception and fall back on the new
// security model's decision.
nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID()));
if (xpc) {
nsCOMPtr<nsIXPCNativeCallContext> cc;
xpc->GetCurrentNativeCallContext(getter_AddRefs(cc));
if (cc) {
JSContext* cx;
rv = cc->GetJSContext(&cx);
NS_ENSURE_SUCCESS(rv, rv);
JS_ClearPendingException(cx);
cc->SetExceptionWasThrown(PR_FALSE);
}
}
}
mServiceURI = aTransportURI;
nsXPIDLCString path;
@ -275,8 +134,36 @@ nsWebScriptsAccess::CanAccess(nsIURI* aTransportURI,
path += '/';
AccessInfoEntry* entry = 0;
rv = GetAccessInfoEntry(path, PR_FALSE, &entry);
NS_ENSURE_SUCCESS(rv, rv);
rv = GetAccessInfoEntry(path, &entry);
if (!entry) {
rv = mSecurityManager->CheckSameOrigin(0, aTransportURI);
if (NS_SUCCEEDED(rv)) {
// script security manager has granted access
*aAccessGranted = PR_TRUE;
return rv;
}
else {
// Script security manager has denied access and has set an
// exception. Clear the exception and fall back on the new
// security model's decision.
nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID()));
if (xpc) {
nsCOMPtr<nsIXPCNativeCallContext> cc;
xpc->GetCurrentNativeCallContext(getter_AddRefs(cc));
if (cc) {
JSContext* cx;
rv = cc->GetJSContext(&cx);
NS_ENSURE_SUCCESS(rv, rv);
JS_ClearPendingException(cx);
cc->SetExceptionWasThrown(PR_FALSE);
}
}
}
rv = CreateEntry(path, PR_FALSE, &entry);
NS_ENSURE_SUCCESS(rv, rv);
}
return CheckAccess(entry, aRequestType, aAccessGranted);
}
@ -301,86 +188,24 @@ nsWebScriptsAccess::InvalidateCache(const char* aTransportURI)
nsresult
nsWebScriptsAccess::GetAccessInfoEntry(const char* aKey,
const PRBool aIsDelegated,
AccessInfoEntry** aEntry)
{
nsCStringKey key(aKey);
*aEntry = NS_REINTERPRET_CAST(AccessInfoEntry*, mAccessInfoTable.Get(&key));
if (!*aEntry) {
// There's no entry for this server. Load the declaration file (
// web-scripts-access.xml ) and extract access information from
// it. Record the extracted info. for this session
nsCOMPtr<nsIDOMDocument> document;
nsresult rv =
GetDocument(PromiseFlatCString(nsDependentCString(aKey) +
NS_LITERAL_CSTRING("web-scripts-access.xml")).get(),
getter_AddRefs(document));
if (*aEntry && ((*aEntry)->mFlags & WSA_FILE_DELEGATED)) {
nsresult rv;
nsCOMPtr<nsIURL> url(do_QueryInterface(mServiceURI, &rv));
NS_ENSURE_SUCCESS(rv, rv);
if (document) {
// Extract access information from the document.
rv = GetInfoFromDocument(document, aIsDelegated, aEntry);
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString path;
url->GetPrePath(path);
nsCAutoString directory;
url->GetDirectory(directory);
path += directory;
// If the document is invalid then an entry will not be created.
if (!*aEntry)
return NS_OK;
}
else {
rv = CreateAccessInfoEntry(WSA_FILE_NOT_FOUND, aEntry);
NS_ENSURE_SUCCESS(rv, rv);
}
mAccessInfoTable.Put(&key, *aEntry);
return GetAccessInfoEntry(path.get(), aEntry);
}
NS_ASSERTION(*aEntry, "unexpected: access info entry is null!");
if (*aEntry && ((*aEntry)->mFlags & WSA_FILE_DELEGATED))
return GetDelegatedInfo(aEntry);
return NS_OK;
}
nsresult
nsWebScriptsAccess::GetInfoFromDocument(nsIDOMDocument* aDocument,
const PRBool aIsDelegated,
AccessInfoEntry** aEntry)
{
NS_ENSURE_ARG_POINTER(aDocument);
PRBool valid;
nsresult rv = ValidateDocument(aDocument, &valid);
NS_ENSURE_SUCCESS(rv, rv);
if (!valid) {
return NS_OK;
}
if (!aIsDelegated) {
nsCOMPtr<nsIDOMNodeList> delegateList;
rv = aDocument->GetElementsByTagNameNS(kNamespace2002, kDelegateTag,
getter_AddRefs(delegateList));
NS_ENSURE_TRUE(delegateList, rv);
nsCOMPtr<nsIDOMNode> node;
delegateList->Item(0, getter_AddRefs(node));
if (node) {
rv = CreateAccessInfoEntry(WSA_FILE_DELEGATED, aEntry);
return rv;
}
}
nsCOMPtr<nsIDOMNodeList> allowList;
rv = aDocument->GetElementsByTagNameNS(kNamespace2002, kAllowTag,
getter_AddRefs(allowList));
NS_ENSURE_TRUE(allowList, rv);
PRUint32 count;
allowList->GetLength(&count);
if (count) {
rv = CreateAccessInfoEntry(allowList, aEntry);
}
else {
// Since there are no ALLOW elements present grant access to all.
rv = CreateAccessInfoEntry(WSA_GRANT_ACCESS_TO_ALL, aEntry);
}
return NS_OK;
}
@ -444,25 +269,93 @@ nsWebScriptsAccess::GetCodebaseURI(nsIURI** aCodebase)
return NS_OK;
}
nsresult
nsWebScriptsAccess::GetDelegatedInfo(AccessInfoEntry** aEntry)
nsresult
nsWebScriptsAccess::CreateEntry(const char* aKey,
const PRBool aIsDelegated,
AccessInfoEntry** aEntry)
{
nsresult rv;
nsCOMPtr<nsIURL> url(do_QueryInterface(mServiceURI, &rv));
NS_ENSURE_ARG_POINTER(aEntry);
*aEntry = nsnull;
// create an entry by loading the declaration file (
// web-scripts-access.xml ) and extracting access information from
// it. Record the extracted info. for this session
nsCOMPtr<nsIDOMDocument> document;
nsresult rv =
GetDocument(PromiseFlatCString(nsDependentCString(aKey) +
NS_LITERAL_CSTRING("web-scripts-access.xml")).get(),
getter_AddRefs(document));
NS_ENSURE_SUCCESS(rv, rv);
nsXPIDLCString path;
url->GetPrePath(path);
nsXPIDLCString directory;
url->GetDirectory(directory);
path += directory;
if (document) {
// Create an entry by extracting access information from the document.
rv = CreateEntry(document, aIsDelegated, aEntry);
NS_ENSURE_SUCCESS(rv, rv);
return GetAccessInfoEntry(path, PR_TRUE, aEntry);
// If the document is invalid then an entry will not be created.
if (!*aEntry)
return NS_OK;
}
else {
rv = CreateEntry(WSA_FILE_NOT_FOUND, aEntry);
NS_ENSURE_SUCCESS(rv, rv);
}
nsCStringKey key(aKey);
mAccessInfoTable.Put(&key, *aEntry);
NS_ASSERTION(*aEntry, "unexpected: access info entry is null!");
if (*aEntry && ((*aEntry)->mFlags & WSA_FILE_DELEGATED))
rv = CreateDelegatedEntry(aEntry);
return rv;
}
nsresult
nsWebScriptsAccess::CreateEntry(nsIDOMDocument* aDocument,
const PRBool aIsDelegated,
AccessInfoEntry** aEntry)
{
NS_ENSURE_ARG_POINTER(aDocument);
NS_ENSURE_ARG_POINTER(aEntry);
*aEntry = nsnull;
PRBool valid;
nsresult rv = ValidateDocument(aDocument, &valid);
NS_ENSURE_SUCCESS(rv, rv);
if (!valid) {
return NS_OK; // XXX should I return an error instead ?
}
if (!aIsDelegated) {
nsCOMPtr<nsIDOMNodeList> delegateList;
rv = aDocument->GetElementsByTagNameNS(kNamespace2002, kDelegateTag,
getter_AddRefs(delegateList));
NS_ENSURE_TRUE(delegateList, rv);
nsCOMPtr<nsIDOMNode> node;
delegateList->Item(0, getter_AddRefs(node));
if (node)
return CreateEntry(WSA_FILE_DELEGATED, aEntry);
}
nsCOMPtr<nsIDOMNodeList> allowList;
rv = aDocument->GetElementsByTagNameNS(kNamespace2002, kAllowTag,
getter_AddRefs(allowList));
NS_ENSURE_TRUE(allowList, rv);
PRUint32 count;
allowList->GetLength(&count);
if (count) {
rv = CreateEntry(allowList, aEntry);
}
else {
// Since there are no ALLOW elements present grant access to all.
rv = CreateEntry(WSA_GRANT_ACCESS_TO_ALL, aEntry);
}
return rv;
}
nsresult
nsWebScriptsAccess::CreateAccessInfoEntry(const PRInt32 aFlags,
AccessInfoEntry** aEntry)
nsWebScriptsAccess::CreateEntry(const PRInt32 aFlags,
AccessInfoEntry** aEntry)
{
*aEntry = new AccessInfoEntry(aFlags);
NS_ENSURE_TRUE(*aEntry, NS_ERROR_OUT_OF_MEMORY);
@ -471,11 +364,13 @@ nsWebScriptsAccess::CreateAccessInfoEntry(const PRInt32 aFlags,
}
nsresult
nsWebScriptsAccess::CreateAccessInfoEntry(nsIDOMNodeList* aAllowList,
AccessInfoEntry** aEntry)
nsWebScriptsAccess::CreateEntry(nsIDOMNodeList* aAllowList,
AccessInfoEntry** aEntry)
{
NS_ENSURE_ARG_POINTER(aAllowList);
NS_ENSURE_ARG_POINTER(aEntry);
*aEntry = nsnull;
nsAutoPtr<AccessInfoEntry> entry(new AccessInfoEntry());
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
@ -529,6 +424,25 @@ nsWebScriptsAccess::CreateAccessInfoEntry(nsIDOMNodeList* aAllowList,
return NS_OK;
}
nsresult
nsWebScriptsAccess::CreateDelegatedEntry(AccessInfoEntry** aEntry)
{
NS_ENSURE_ARG_POINTER(aEntry);
*aEntry = nsnull;
nsresult rv;
nsCOMPtr<nsIURL> url(do_QueryInterface(mServiceURI, &rv));
NS_ENSURE_SUCCESS(rv, rv);
nsCAutoString path;
url->GetPrePath(path);
nsCAutoString directory;
url->GetDirectory(directory);
path += directory;
return CreateEntry(path.get(), PR_TRUE, aEntry);
}
nsresult
nsWebScriptsAccess::CheckAccess(AccessInfoEntry* aEntry,
const nsAString& aRequestType,
@ -538,24 +452,44 @@ nsWebScriptsAccess::CheckAccess(AccessInfoEntry* aEntry,
static PRBool verified = PR_FALSE;
if (!verified) {
verified = PR_TRUE;
VerifyIsEqual();
nsWSAUtils::VerifyIsEqual();
}
#endif
*aAccessGranted = PR_FALSE;
NS_ENSURE_ARG_POINTER(aEntry);
nsresult rv = NS_OK;
if (aEntry->mFlags & WSA_FILE_NOT_FOUND) {
return NS_OK;
}
if (aEntry->mFlags & HAS_MASTER_SERVICE_DECISION) {
if (aEntry->mFlags & SERVICE_LISTED_PUBLIC)
*aAccessGranted = PR_TRUE;
return rv;
}
nsCAutoString fqdn;
rv = nsWSAUtils::GetOfficialHostName(mServiceURI, fqdn);
if (NS_FAILED(rv) || fqdn.IsEmpty())
return rv;
PRBool isPublic = PR_FALSE;
rv = IsPublicService(fqdn.get(), &isPublic);
if (NS_SUCCEEDED(rv)) {
if (isPublic) {
aEntry->mFlags |= SERVICE_LISTED_PUBLIC;
*aAccessGranted = PR_TRUE;
}
aEntry->mFlags |= HAS_MASTER_SERVICE_DECISION;
}
return rv;
}
if (aEntry->mFlags & WSA_GRANT_ACCESS_TO_ALL) {
*aAccessGranted = PR_TRUE;
return NS_OK;
}
nsCOMPtr<nsIURI> codebase_uri;
nsresult rv = GetCodebaseURI(getter_AddRefs(codebase_uri));
rv = GetCodebaseURI(getter_AddRefs(codebase_uri));
NS_ENSURE_SUCCESS(rv, rv);
nsXPIDLCString tmp;
@ -577,14 +511,15 @@ nsWebScriptsAccess::CheckAccess(AccessInfoEntry* aEntry,
break;
}
else {
if (IsEqual(nsDependentString(access_info->mFrom), codebase)) {
if (nsWSAUtils::IsEqual(nsDependentString(access_info->mFrom),
codebase)) {
*aAccessGranted = PR_TRUE;
break;
}
}
}
}
return NS_OK;
}
@ -618,13 +553,15 @@ nsWebScriptsAccess::ValidateDocument(nsIDOMDocument* aDocument,
if (!ns.Equals(kNamespace2002)) {
const PRUnichar *inputs[1] = { ns.get() };
return ReportError(NS_LITERAL_STRING("UnsupportedNamespace").get(),
inputs, 1);
return nsWSAUtils::ReportError(
NS_LITERAL_STRING("UnsupportedNamespace").get(),
inputs, 1);
}
if (!name.Equals(kWebScriptAccessTag)) {
const PRUnichar *inputs[1] = { name.get() };
return ReportError(NS_LITERAL_STRING("UnknownRootElement").get(),
inputs, 1);
return nsWSAUtils::ReportError(
NS_LITERAL_STRING("UnknownRootElement").get(),
inputs, 1);
}
nsCOMPtr<nsIDOMNode> rootNode(do_QueryInterface(rootElement));
@ -664,15 +601,17 @@ nsWebScriptsAccess::ValidateDocument(nsIDOMDocument* aDocument,
// There can me no more than one delegate element.
if (hadDelegate) {
const PRUnichar *inputs[1] = { name.get() };
return ReportError(NS_LITERAL_STRING("TooManyElements").get(),
inputs, 1);
return nsWSAUtils::ReportError(
NS_LITERAL_STRING("TooManyElements").get(),
inputs, 1);
}
// Make sure that the delegate element is EMPTY.
child->HasChildNodes(&hasChildNodes);
if (hasChildNodes) {
const PRUnichar *inputs[1] = { name.get() };
return ReportError(NS_LITERAL_STRING("ElementNotEmpty").get(),
inputs, 1);
return nsWSAUtils::ReportError(
NS_LITERAL_STRING("ElementNotEmpty").get(),
inputs, 1);
}
hadDelegate = PR_TRUE;
}
@ -681,8 +620,9 @@ nsWebScriptsAccess::ValidateDocument(nsIDOMDocument* aDocument,
child->HasChildNodes(&hasChildNodes);
if (hasChildNodes) {
const PRUnichar *inputs[1] = { name.get() };
return ReportError(NS_LITERAL_STRING("ElementNotEmpty").get(),
inputs, 1);
return nsWSAUtils::ReportError(
NS_LITERAL_STRING("ElementNotEmpty").get(),
inputs, 1);
}
rv = child->GetAttributes(getter_AddRefs(attrs));
if (NS_FAILED(rv))
@ -698,16 +638,18 @@ nsWebScriptsAccess::ValidateDocument(nsIDOMDocument* aDocument,
return rv;
if (!name.Equals(kTypeAttr) && !name.Equals(kFromAttr)) {
const PRUnichar *inputs[1] = { name.get() };
return ReportError(NS_LITERAL_STRING("UnknownAttribute").get(),
inputs, 1);
return nsWSAUtils::ReportError(
NS_LITERAL_STRING("UnknownAttribute").get(),
inputs, 1);
}
}
}
}
else {
const PRUnichar *inputs[1] = { name.get() };
return ReportError(NS_LITERAL_STRING("UnknownElement").get(),
inputs, 1);
return nsWSAUtils::ReportError(
NS_LITERAL_STRING("UnknownElement").get(),
inputs, 1);
}
}
@ -716,27 +658,197 @@ nsWebScriptsAccess::ValidateDocument(nsIDOMDocument* aDocument,
return NS_OK;
}
nsresult
nsWebScriptsAccess::ReportError(const PRUnichar* aMessageID,
const PRUnichar** aInputs,
const PRInt32 aLength)
static PRBool
IsCharInSet(const char* aSet,
const PRUnichar aChar)
{
nsCOMPtr<nsIStringBundleService> bundleService
= do_GetService(NS_STRINGBUNDLE_CONTRACTID);
NS_ENSURE_TRUE(bundleService, NS_OK); // intentionally returning NS_OK;
nsCOMPtr<nsIStringBundle> bundle;
bundleService->CreateBundle(SECURITY_PROPERTIES, getter_AddRefs(bundle));
NS_ENSURE_TRUE(bundle, NS_OK);
nsXPIDLString message;
bundle->FormatStringFromName(aMessageID, aInputs, aLength,
getter_Copies(message));
nsCOMPtr<nsIConsoleService> consoleService =
do_GetService(NS_CONSOLESERVICE_CONTRACTID);
NS_ENSURE_TRUE(consoleService, NS_OK); // intentionally returning NS_OK;
return consoleService->LogStringMessage(message.get());
PRUnichar ch;
while ((ch = *aSet)) {
if (aChar == PRUnichar(ch)) {
return PR_TRUE;
}
++aSet;
}
return PR_FALSE;
}
nsresult
nsWebScriptsAccess::IsPublicService(const char* aHost, PRBool* aReturn)
{
*aReturn = PR_FALSE;
nsresult rv = NS_OK;
// Cache the master services included in the prefs.
if (mMasterServices.Count() == 0) {
nsCOMPtr<nsIPrefBranch> prefBranch =
do_GetService(NS_PREFSERVICE_CONTRACTID);
if (!prefBranch)
return rv;
nsXPIDLCString value;
rv = prefBranch->GetCharPref("xml.webservice.security.masterservices",
getter_Copies(value));
if (NS_FAILED(rv) || value.IsEmpty())
return rv;
nsACString::const_iterator begin, end, curr;
nsACString::const_iterator uri_begin, uri_end;
value.BeginReading(begin);
value.EndReading(end);
// Parse the comma separated pref. value
static const char* kWhitespace = " \n\r\t\b";
while (begin != end) {
curr = begin;
// strip leading whitespaces
while (IsCharInSet(kWhitespace, *curr) && ++curr != end);
uri_begin = curr;
// consume until the delimiter ( comma ).
while (curr != end && *curr != ',')
++curr;
uri_end = curr;
// strip trailing whitespaces
while (uri_end != uri_begin) {
if (!IsCharInSet(kWhitespace, *(--uri_end))) {
++uri_end; // include the last non whitespace char.
break;
}
}
const nsAFlatString& transportURI =
NS_ConvertUTF8toUCS2(Substring(uri_begin, uri_end));
if (!transportURI.IsEmpty())
mMasterServices.AppendString(transportURI);
begin = (*curr == ',' && curr != end) ? ++curr : curr;
}
}
// Allocate param block.
nsISOAPParameter** bodyBlocks =
NS_STATIC_CAST(nsISOAPParameter**,
nsMemory::Alloc(1 * sizeof(nsISOAPParameter*)));
if (!bodyBlocks)
return NS_ERROR_OUT_OF_MEMORY;
rv =
CallCreateInstance(NS_SOAPPARAMETER_CONTRACTID, &bodyBlocks[0]);
if (NS_FAILED(rv)) {
NS_FREE_XPCOM_ISUPPORTS_POINTER_ARRAY(0, bodyBlocks);
return rv;
}
nsCOMPtr<nsISOAPBlock> block = do_QueryInterface(bodyBlocks[0], &rv);
if (NS_FAILED(rv))
return rv;
block->SetName(NS_LITERAL_STRING("fqdn"));
nsCOMPtr <nsIWritableVariant> variant =
do_CreateInstance(NS_VARIANT_CONTRACTID, &rv);
if (NS_FAILED(rv))
return rv;
variant->SetAsString(aHost);
block->SetValue(variant);
// Create the call instance
nsCOMPtr<nsISOAPCall> call =
do_CreateInstance(NS_SOAPCALL_CONTRACTID, &rv);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsISOAPEncoding> encoding =
do_CreateInstance(NS_SOAPENCODING_CONTRACTID, &rv);
if (NS_FAILED(rv))
return rv;
call->SetEncoding(encoding);
// Since the SOAP request to the central server will be made
// from the native code we can safely override cross-domain
// checks by pushing in a null jscontext on the context stack.
nsCOMPtr<nsIJSContextStack> stack =
do_GetService("@mozilla.org/js/xpc/ContextStack;1");
if (stack)
stack->Push(nsnull);
nsCOMPtr<nsISOAPResponse> response;
PRInt32 i, count = mMasterServices.Count();
for (i = 0; i < count && !response; i++) {
rv =
call->SetTransportURI(*mMasterServices.StringAt(i));
if (NS_FAILED(rv))
break;
rv = call->Encode(nsISOAPMessage::VERSION_1_1,
kIsServicePublic,
kNamespace2002, // The target URI
0, 0, 1, bodyBlocks);
if (NS_FAILED(rv))
break;
call->Invoke(getter_AddRefs(response)); // XXX - How to handle time out and 404?
}
if (stack) {
JSContext* cx;
stack->Pop(&cx);
NS_ASSERTION(!cx, "context should be null");
}
if (!response)
return rv;
nsCOMPtr<nsISOAPFault> fault;
response->GetFault(getter_AddRefs(fault));
if (fault) {
nsAutoString faultNamespaceURI, faultCode, faultString;
fault->GetFaultNamespaceURI(faultNamespaceURI);
fault->GetFaultCode(faultCode);
fault->GetFaultString(faultString);
const PRUnichar *inputs[5] =
{
kNamespace2002.get(),
kIsServicePublic.get(),
faultNamespaceURI.get(),
faultCode.get(),
faultString.get()
};
return nsWSAUtils::ReportError(
NS_LITERAL_STRING("SOAPFault").get(),
inputs, 5);
}
else {
PRUint32 bodyCount;
rv = response->GetParameters(PR_FALSE, &bodyCount, &bodyBlocks);
NS_ASSERTION(bodyBlocks, "insufficient information");
if (!bodyBlocks || NS_FAILED(rv))
return rv;
NS_ASSERTION(bodyCount == 1, "body seems to contain unnecessary information.");
block = do_QueryInterface(bodyBlocks[0], &rv);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIVariant> value;
rv = block->GetValue(getter_AddRefs(value));
if (NS_FAILED(rv) || !value)
return rv;
rv = value->GetAsBool(aReturn);
}
return rv;
}

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

@ -38,13 +38,12 @@
#ifndef nsWebScriptsAccess_h__
#define nsWebScriptsAccess_h__
#include "nsCOMPtr.h"
#include "nsIURI.h"
#include "nsIWebScriptsAccessService.h"
#include "nsIScriptSecurityManager.h"
#include "nsHashtable.h"
#include "nsIXMLHttpRequest.h"
#include "nsVoidArray.h"
#include "nsWSAUtils.h"
class nsIDOMDocument;
class nsIDOMNode;
@ -98,20 +97,22 @@ public:
NS_DECL_NSIWEBSCRIPTSACCESSSERVICE
protected:
nsresult CheckAccess(AccessInfoEntry* aAccessInfoEntry, const nsAString& aRequestType, PRBool* aAccessGranted);
nsresult GetAccessInfoEntry(const char* aKey, const PRBool aIsDelegated, AccessInfoEntry** aEntry);
nsresult GetInfoFromDocument(nsIDOMDocument* aDocument, const PRBool aIsDelegated, AccessInfoEntry** aAccessInfoEntry);
nsresult GetAccessInfoEntry(const char* aKey, AccessInfoEntry** aEntry);
nsresult GetDocument(const char* aDeclFilePath, nsIDOMDocument** aDocument);
nsresult GetCodebaseURI(nsIURI** aCodebase);
nsresult GetDelegatedInfo(AccessInfoEntry** aAccessInfoEntry);
nsresult CreateAccessInfoEntry(nsIDOMNodeList* aAllowList, AccessInfoEntry** aAccessInfoEntry);
nsresult CreateAccessInfoEntry(const PRInt32 aFlags, AccessInfoEntry** aAccessInfoEntry);
nsresult ReportError(const PRUnichar* aMessageID, const PRUnichar** aInputs, const PRInt32 aLength);
nsresult CreateEntry(const char* aKey, const PRBool aIsDelegated, AccessInfoEntry** aEntry);
nsresult CreateEntry(nsIDOMDocument* aDocument, const PRBool aIsDelegated, AccessInfoEntry** aAccessInfoEntry);
nsresult CreateEntry(nsIDOMNodeList* aAllowList, AccessInfoEntry** aAccessInfoEntry);
nsresult CreateEntry(const PRInt32 aFlags, AccessInfoEntry** aAccessInfoEntry);
nsresult CreateDelegatedEntry(AccessInfoEntry** aAccessInfoEntry);
nsresult CheckAccess(AccessInfoEntry* aAccessInfoEntry, const nsAString& aRequestType, PRBool* aAccessGranted);
nsresult ValidateDocument(nsIDOMDocument* aDocument, PRBool* aIsValid);
nsresult IsPublicService(const char* aHost, PRBool* aReturn);
nsCOMPtr<nsIURI> mServiceURI;
nsCOMPtr<nsIXMLHttpRequest> mRequest;
nsCOMPtr<nsIScriptSecurityManager> mSecurityManager;
nsStringArray mMasterServices;
nsHashtable mAccessInfoTable;
};

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

@ -41,4 +41,5 @@ UnknownAttribute = The attribute "%S" is not recognized.
TooManyElements = There can be no more than one "%S" element.
ElementHasSibling = "%S" element cannot have "%S" sibiling.
ElementNotEmpty = The "%S" element should be empty.
SOAPFault = SOAP { %S } %S call resulted in fault: { %S } %S : %S.