Tuesday, March 29, 2011 at 1:07 AM.

river2Suite.firewall

on firewall (pta) {
	<<Changes
		<<3/27/11; 7:10:40 PM by DW
			<<Switch to cookie-based user authentication.
				<<Old code
					<<local (adrdata = river2suite.init ())
					<<scratchpad.firewallparams = pta^
					<<if pta^.adrobject == @river2Website.cloudPipeServer //handles its own security -- 12/23/09 by DW
						<<return (true)
					<<on getHostFromReferer (referer)
						<<local (urllist, host)
						<<try
							<<urllist = string.urlsplit (pta^.requestHeaders.referer)
						<<else
							<<urllist = string.urlsplit (pta^.requestHeaders.referer + "/")
						<<host = urllist [2]
						<<if host contains ":"
							<<host = string.nthField (host, ":", 1)
						<<return (host)
					<<if not defined (pta^.river2)
						<<new (tabletype, @pta^.river2)
					<<pta^.river2.flSameMachine = opmlEditor.isSameMachine (pta^.client)
					<<if pta^.river2.flSameMachine //other code can look at this
						<<return (true)
					<<if defined (pta^.river2.flStaticBuild) //3/18/10 by DW
						<<if pta^.river2.flStaticBuild
							<<return (true)
					<<local (username, password)
					<<bundle //set username, password
						<<if pta^.adruser == nil
							<<username = nil
							<<password = nil
						<<else
							<<username = nameof (pta^.adruser^)
							<<password = pta^.adruser^.prefs.password
					<<return (opmleditor.firewall (pta, username, password))
		<<3/1/11; 10:16:16 AM by DW
			<<Gutted. We pass off the job to the opmleditor.firewall.
				<<Old code
					<<on firewall (pta)
						<<Changes
							<<3/1/11; 10:16:16 AM by DW
								<<Gutted. We pass off the job to the opmleditor.firewall.
									<<Old code
							<<4/22/10; 10:56:23 AM by DW
								<<If adruser is not nil (there's a "user" parameter on the request), the request must have the correct password for that user. 
							<<3/18/10; 11:32:49 AM by DW
								<<If it's a static build, let it pass through the firewall.
							<<12/23/09; 11:01:28 AM by DW
								<<If the call is going to the cloudPipe server, return true -- allowing it to handle its own security.
							<<11/5/09; 11:45:47 AM by DW
								<<Commented a section that checks referrers if you're accessing it on the same machine. I don't understand what it's protecting against, but the policy of River2 is to give full power to the user on the local machine. He has it anyway (he can go into the object database directly). 
							<<8/26/09; 9:14:21 AM by DW
								<<It's "flAllowRemotePost" not "allowRemotePost" -- shouldn't do big stuff when you have a bad code Davey. :-)
							<<8/22/09; 6:03:25 PM by DW
								<<Minor fixes.
							<<8/21/09; 11:44:09 AM by DW
								<<Fixes. (More to come.)
							<<8/21/09; 11:18:41 AM by DW
								<<Implement the firewall.
							<<4/21/02; 11:42:50 PM by JES
								<<Fixed a bug which would errorneously deny access when making a POST via the desktop website as accessed through the domain name instead of through its IP address.
							<<3/7/02; 10:07:38 PM by JES
								<<Follow address values when running callbacks.
							<<2/10/02; 12:36:47 PM by DW
								<<Added support for callbacks.
									<<http://radio.userland.com/stories/storyReader$10132
							<<2/10/02; 12:22:18 PM by DW
								<<Add support for callbacks.
							<<1/23/02; 12:59:03 PM by JES
								<<When checking referers for POST requests, allow requests through if the referer is non-local, and Radio's IP address is a standard NAT IP address. This fixes a problem where people running Radio with NAT and port forwarding could not POST remotely.
							<<1/22/02; 1:22:05 PM by DW
								<<Handle referers without trailing slash (e.g. http://127.0.0.1).
							<<1/21/02; 2:24:39 PM by JES
								<<Don't use tcp.equalNames when checking the referer on POSTs, because it failed for some proxy server users.
							<<1/18/02; 11:37:24 AM by DW
								<<Security issue: Closes a hole where a form appears on another site, and the user unknowingly posts to his Radio 8 site. With this fix, the referer on every post must be on the machine that Radio is running on, or a 500 server error is returned. More info, if available, will be posted here.
									<<http://frontier.userland.com/securityAlerts/remoteFormRadio
							<<1/7/02; 11:43:42 PM by JES
								<<If adrdata^.prefs.security.allowRemoteSystemPageAccess is false, and pta^.path begins with /system/ (case-insensitive), access is denied.
							<<7/26/01; 3:28:15 PM by JES
								<<Changed the logical interpretation of the security prefs. Here's the summary:
									<<If you're on the same machine as Radio, you are always allowed in.
									<<If allowRemoteViewing is false, you are never allowed in.
									<<If this is a POST, and allowRemotePost is false, you're not allowed.
									<<If requireRemoteLogin is true *or* this is a POST, you get an authentication challenge.
									<<If you fail authorization, you're not allowed.
							<<6/9/01; 2:38:09 PM by DW
								<<Created. Make sure the user is allowed to access.
								<<Two ways to return -- either by scriptError'ing, canceling the whole operation; or returning false which allows you to talk to the client for security authorization.
						<<bundle //call the callbacks
							<<local (adr)
							<<for adr in @user.radio.callbacks.firewall
								<<try
									<<while typeOf (adr^) == addressType
										<<adr = adr^
									<<if adr^ (pta)
										<<return (true)
						<<local (adrdata = river2suite.init ())
						<<scratchpad.firewallparams = pta^
						<<if pta^.adrobject == @river2Website.cloudPipeServer //handles its own security -- 12/23/09 by DW
							<<return (true)
						<<on getHostFromReferer (referer)
							<<local (urllist, host)
							<<try
								<<urllist = string.urlsplit (pta^.requestHeaders.referer)
							<<else
								<<urllist = string.urlsplit (pta^.requestHeaders.referer + "/")
							<<host = urllist [2]
							<<if host contains ":"
								<<host = string.nthField (host, ":", 1)
							<<return (host)
						<<bundle //init pta^.river2
							<<if not defined (pta^.river2)
								<<new (tabletype, @pta^.river2)
							<<bundle //set flSameMachine
								<<local (flSameMachine = false)
								<<local (client = pta^.client)
								<<if string.lower (client) == "localhost"
									<<flSameMachine = true
								<<else
									<<if client == "127.0.0.1"
										<<flSameMachine = true
									<<else
										<<try {flSameMachine = tcp.equalNames (client, tcp.myDottedID ())} 
								<<pta^.river2.flSameMachine = flSameMachine
						<<if pta^.river2.flSameMachine  //commented -- 11/5/09 by DW
							<<if pta^.method == "POST" //hole closed, 1/18/02 DW
								<<local (refererhost = getHostFromReferer (pta^.requestHeaders.referer))
								<<if refererhost != "127.0.0.1"
									<<if string.lower (refererhost) != "localhost"
										<<scriptError ("Access denied.")
							<<return (true)
						<<if defined (pta^.river2.flStaticBuild) //3/18/10 by DW
							<<if pta^.river2.flStaticBuild
								<<return (true)
						<<if not adrdata^.prefs.security.flAllowRemoteViewing
							<<scriptError ("Access denied.")
						<<if pta^.method == "POST"
							<<if not adrdata^.prefs.security.flAllowRemotePost
								<<scriptError ("Access denied.")
						<<if adrdata^.prefs.security.flRequireRemoteLogin or (pta^.method == "POST")
							<<local (flsecure = false)
							<<if webserver.util.parseAuth (pta) //get username and password
								<<if pta^.adruser != nil //4/22/10 by DW -- user-level authentication
									<<if string.lower (pta^.username) == string.lower (nameof (pta^.adruser^))
										<<if string (pta^.password) == string (pta^.adruser^.prefs.password)
											<<flsecure = true
								<<else
									<<if string.lower (pta^.username) == string.lower (adrdata^.prefs.security.remoteUsername)
										<<if string (pta^.password) == string (adrdata^.prefs.security.remotePassword)
											<<flsecure = true
							<<if not flsecure //send challenge
								<<pta^.responseBody = webserver.util.buildErrorPage ("401 Unauthorized", "A valid username and password are required to access this page.")
								<<pta^.responseHeaders.["WWW-Authenticate"] = "Basic realm=\"Admin\""
								<<pta^.code = 401
								<<return (false)
							<<if pta^.method == "POST" //1/23/02 JES: check non-local referers
								<<try //some users behind proxy servers can't do DNS lookups -- don't do a 500 Server Error
									<<local (refererhost = getHostFromReferer (pta^.requestHeaders.referer))
									<<if refererhost != tcp.dns.getMyDottedId ()
										<<if not tcp.equalNames (refererhost, tcp.dns.getMyDottedId ())
											<<scriptError ("Access denied.")
								<<else //check for local NAT IP addresses, as defined by ICANN
									<<Reference: http://www.riverstonenet.com/technology/nat.shtml
									<<local (myIp = tcp.dns.getMyDottedId ())
									<<if myIp beginsWith "10." //10.x.x.x is ok. (Class A)
										<<return (true)
									<<if myIp beginsWith "172." //172.31.0.0 to 172.31.255.255 are ok. (Class B)
										<<local (x = number (string.nthField (myIp, ".", 2)))
										<<if x >= 0 and x <= 31
											<<return (true)
									<<if myIp beginsWith "192.168." //192.168.x.x is ok. (Class C)
										<<return (true)
									<<scriptError ("Access denied.")
						<<return (true)
		<<4/22/10; 10:56:23 AM by DW
			<<If adruser is not nil (there's a "user" parameter on the request), the request must have the correct password for that user. 
		<<3/18/10; 11:32:49 AM by DW
			<<If it's a static build, let it pass through the firewall.
		<<12/23/09; 11:01:28 AM by DW
			<<If the call is going to the cloudPipe server, return true -- allowing it to handle its own security.
		<<11/5/09; 11:45:47 AM by DW
			<<Commented a section that checks referrers if you're accessing it on the same machine. I don't understand what it's protecting against, but the policy of River2 is to give full power to the user on the local machine. He has it anyway (he can go into the object database directly). 
		<<8/26/09; 9:14:21 AM by DW
			<<It's "flAllowRemotePost" not "allowRemotePost" -- shouldn't do big stuff when you have a bad code Davey. :-)
		<<8/22/09; 6:03:25 PM by DW
			<<Minor fixes.
		<<8/21/09; 11:44:09 AM by DW
			<<Fixes. (More to come.)
		<<8/21/09; 11:18:41 AM by DW
			<<Implement the firewall.
		<<4/21/02; 11:42:50 PM by JES
			<<Fixed a bug which would errorneously deny access when making a POST via the desktop website as accessed through the domain name instead of through its IP address.
		<<3/7/02; 10:07:38 PM by JES
			<<Follow address values when running callbacks.
		<<2/10/02; 12:36:47 PM by DW
			<<Added support for callbacks.
				<<http://radio.userland.com/stories/storyReader$10132
		<<2/10/02; 12:22:18 PM by DW
			<<Add support for callbacks.
		<<1/23/02; 12:59:03 PM by JES
			<<When checking referers for POST requests, allow requests through if the referer is non-local, and Radio's IP address is a standard NAT IP address. This fixes a problem where people running Radio with NAT and port forwarding could not POST remotely.
		<<1/22/02; 1:22:05 PM by DW
			<<Handle referers without trailing slash (e.g. http://127.0.0.1).
		<<1/21/02; 2:24:39 PM by JES
			<<Don't use tcp.equalNames when checking the referer on POSTs, because it failed for some proxy server users.
		<<1/18/02; 11:37:24 AM by DW
			<<Security issue: Closes a hole where a form appears on another site, and the user unknowingly posts to his Radio 8 site. With this fix, the referer on every post must be on the machine that Radio is running on, or a 500 server error is returned. More info, if available, will be posted here.
				<<http://frontier.userland.com/securityAlerts/remoteFormRadio
		<<1/7/02; 11:43:42 PM by JES
			<<If adrdata^.prefs.security.allowRemoteSystemPageAccess is false, and pta^.path begins with /system/ (case-insensitive), access is denied.
		<<7/26/01; 3:28:15 PM by JES
			<<Changed the logical interpretation of the security prefs. Here's the summary:
				<<If you're on the same machine as Radio, you are always allowed in.
				<<If allowRemoteViewing is false, you are never allowed in.
				<<If this is a POST, and allowRemotePost is false, you're not allowed.
				<<If requireRemoteLogin is true *or* this is a POST, you get an authentication challenge.
				<<If you fail authorization, you're not allowed.
		<<6/9/01; 2:38:09 PM by DW
			<<Created. Make sure the user is allowed to access.
			<<Two ways to return -- either by scriptError'ing, canceling the whole operation; or returning false which allows you to talk to the client for security authorization.
	local (adrdata = river2suite.init (), username);
	<<scratchpad.firewallparams = pta^
	pta^.adruser = nil;
	new (tabletype, @pta^.river2);
	pta^.river2.flSameMachine = false; //scotch tape
	bundle { //exceptions
		if pta^.adrobject == @river2Website.cloudPipeServer { //handles its own security -- 12/23/09 by DW
			return (true)};
		if pta^.adrobject == @river2Website.signin {
			return (true)};
		if defined (pta^.river2.flStaticBuild) { //3/18/10 by DW
			if pta^.river2.flStaticBuild {
				return (true)}};
		if string.lower (pta^.path) endswith "notify" {
			return (true)}};
	if opmlEditor.member.checkCookie ("signin", @username) {
		pta^.adruser = @adrdata^.users.[username];
		return (true)}
	else {
		return (false)}};
bundle { //test code
	firewall (@scratchpad.firewallparams)}



This listing is for code that runs in the OPML Editor environment. I created these listings because I wanted the search engines to index it, so that when I want to look up something in my codebase I don't have to use the much slower search functionality in my object database. Dave Winer.