You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							248 lines
						
					
					
						
							6.7 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							248 lines
						
					
					
						
							6.7 KiB
						
					
					
				| <?php | |
| 
 | |
| /* | |
|  | |
| 	Copyright (c) 2009-2019 F3::Factory/Bong Cosca, All rights reserved. | |
|  | |
| 	This file is part of the Fat-Free Framework (http://fatfreeframework.com). | |
|  | |
| 	This is free software: you can redistribute it and/or modify it under the | |
| 	terms of the GNU General Public License as published by the Free Software | |
| 	Foundation, either version 3 of the License, or later. | |
|  | |
| 	Fat-Free Framework is distributed in the hope that it will be useful, | |
| 	but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | |
| 	General Public License for more details. | |
|  | |
| 	You should have received a copy of the GNU General Public License along | |
| 	with Fat-Free Framework.  If not, see <http://www.gnu.org/licenses/>. | |
|  | |
| */ | |
| 
 | |
| namespace Web; | |
| 
 | |
| //! OpenID consumer | |
| class OpenID extends \Magic { | |
| 
 | |
| 	protected | |
| 		//! OpenID provider endpoint URL | |
| 		$url, | |
| 		//! HTTP request parameters | |
| 		$args=[]; | |
| 
 | |
| 	/** | |
| 	*	Determine OpenID provider | |
| 	*	@return string|FALSE | |
| 	*	@param $proxy string | |
| 	**/ | |
| 	protected function discover($proxy) { | |
| 		// Normalize | |
| 		if (!preg_match('/https?:\/\//i',$this->args['endpoint'])) | |
| 			$this->args['endpoint']='http://'.$this->args['endpoint']; | |
| 		$url=parse_url($this->args['endpoint']); | |
| 		// Remove fragment; reconnect parts | |
| 		$this->args['endpoint']=$url['scheme'].'://'. | |
| 			(isset($url['user'])? | |
| 				($url['user']. | |
| 				(isset($url['pass'])?(':'.$url['pass']):'').'@'):''). | |
| 			strtolower($url['host']).(isset($url['path'])?$url['path']:'/'). | |
| 			(isset($url['query'])?('?'.$url['query']):''); | |
| 		// HTML-based discovery of OpenID provider | |
| 		$req=\Web::instance()-> | |
| 			request($this->args['endpoint'],['proxy'=>$proxy]); | |
| 		if (!$req) | |
| 			return FALSE; | |
| 		$type=array_values(preg_grep('/Content-Type:/',$req['headers'])); | |
| 		if ($type && | |
| 			preg_match('/application\/xrds\+xml|text\/xml/',$type[0]) && | |
| 			($sxml=simplexml_load_string($req['body'])) && | |
| 			($xrds=json_decode(json_encode($sxml),TRUE)) && | |
| 			isset($xrds['XRD'])) { | |
| 			// XRDS document | |
| 			$svc=$xrds['XRD']['Service']; | |
| 			if (isset($svc[0])) | |
| 				$svc=$svc[0]; | |
| 			$svc_type=is_array($svc['Type'])?$svc['Type']:array($svc['Type']); | |
| 			if (preg_grep('/http:\/\/specs\.openid\.net\/auth\/2.0\/'. | |
| 					'(?:server|signon)/',$svc_type)) { | |
| 				$this->args['provider']=$svc['URI']; | |
| 				if (isset($svc['LocalID'])) | |
| 					$this->args['localidentity']=$svc['LocalID']; | |
| 				elseif (isset($svc['CanonicalID'])) | |
| 					$this->args['localidentity']=$svc['CanonicalID']; | |
| 			} | |
| 			$this->args['server']=$svc['URI']; | |
| 			if (isset($svc['Delegate'])) | |
| 				$this->args['delegate']=$svc['Delegate']; | |
| 		} | |
| 		else { | |
| 			$len=strlen($req['body']); | |
| 			$ptr=0; | |
| 			// Parse document | |
| 			while ($ptr<$len) | |
| 				if (preg_match( | |
| 					'/^<link\b((?:\h+\w+\h*=\h*'. | |
| 					'(?:"(?:.+?)"|\'(?:.+?)\'))*)\h*\/?>/is', | |
| 					substr($req['body'],$ptr),$parts)) { | |
| 					if ($parts[1] && | |
| 						// Process attributes | |
| 						preg_match_all('/\b(rel|href)\h*=\h*'. | |
| 							'(?:"(.+?)"|\'(.+?)\')/s',$parts[1],$attr, | |
| 							PREG_SET_ORDER)) { | |
| 						$node=[]; | |
| 						foreach ($attr as $kv) | |
| 							$node[$kv[1]]=isset($kv[2])?$kv[2]:$kv[3]; | |
| 						if (isset($node['rel']) && | |
| 							preg_match('/openid2?\.(\w+)/', | |
| 								$node['rel'],$var) && | |
| 							isset($node['href'])) | |
| 							$this->args[$var[1]]=$node['href']; | |
| 
 | |
| 					} | |
| 					$ptr+=strlen($parts[0]); | |
| 				} | |
| 				else | |
| 					$ptr++; | |
| 		} | |
| 		// Get OpenID provider's endpoint URL | |
| 		if (isset($this->args['provider'])) { | |
| 			// OpenID 2.0 | |
| 			$this->args['ns']='http://specs.openid.net/auth/2.0'; | |
| 			if (isset($this->args['localidentity'])) | |
| 				$this->args['identity']=$this->args['localidentity']; | |
| 			if (isset($this->args['trust_root'])) | |
| 				$this->args['realm']=$this->args['trust_root']; | |
| 		} | |
| 		elseif (isset($this->args['server'])) { | |
| 			// OpenID 1.1 | |
| 			$this->args['ns']='http://openid.net/signon/1.1'; | |
| 			if (isset($this->args['delegate'])) | |
| 				$this->args['identity']=$this->args['delegate']; | |
| 		} | |
| 		if (isset($this->args['provider'])) { | |
| 			// OpenID 2.0 | |
| 			if (empty($this->args['claimed_id'])) | |
| 				$this->args['claimed_id']=$this->args['identity']; | |
| 			return $this->args['provider']; | |
| 		} | |
| 		elseif (isset($this->args['server'])) | |
| 			// OpenID 1.1 | |
| 			return $this->args['server']; | |
| 		else | |
| 			return FALSE; | |
| 	} | |
| 
 | |
| 	/** | |
| 	*	Initiate OpenID authentication sequence; Return FALSE on failure | |
| 	*	or redirect to OpenID provider URL | |
| 	*	@return bool | |
| 	*	@param $proxy string | |
| 	*	@param $attr array | |
| 	*	@param $reqd string|array | |
| 	**/ | |
| 	function auth($proxy=NULL,$attr=[],array $reqd=NULL) { | |
| 		$fw=\Base::instance(); | |
| 		$root=$fw->SCHEME.'://'.$fw->HOST; | |
| 		if (empty($this->args['trust_root'])) | |
| 			$this->args['trust_root']=$root.$fw->BASE.'/'; | |
| 		if (empty($this->args['return_to'])) | |
| 			$this->args['return_to']=$root.$_SERVER['REQUEST_URI']; | |
| 		$this->args['mode']='checkid_setup'; | |
| 		if ($this->url=$this->discover($proxy)) { | |
| 			if ($attr) { | |
| 				$this->args['ns.ax']='http://openid.net/srv/ax/1.0'; | |
| 				$this->args['ax.mode']='fetch_request'; | |
| 				foreach ($attr as $key=>$val) | |
| 					$this->args['ax.type.'.$key]=$val; | |
| 				$this->args['ax.required']=is_string($reqd)? | |
| 					$reqd:implode(',',$reqd); | |
| 			} | |
| 			$var=[]; | |
| 			foreach ($this->args as $key=>$val) | |
| 				$var['openid.'.$key]=$val; | |
| 			$fw->reroute($this->url.'?'.http_build_query($var)); | |
| 		} | |
| 		return FALSE; | |
| 	} | |
| 
 | |
| 	/** | |
| 	*	Return TRUE if OpenID verification was successful | |
| 	*	@return bool | |
| 	*	@param $proxy string | |
| 	**/ | |
| 	function verified($proxy=NULL) { | |
| 		preg_match_all('/(?<=^|&)openid\.([^=]+)=([^&]+)/', | |
| 			$_SERVER['QUERY_STRING'],$matches,PREG_SET_ORDER); | |
| 		foreach ($matches as $match) | |
| 			$this->args[$match[1]]=urldecode($match[2]); | |
| 		if (isset($this->args['mode']) && | |
| 			$this->args['mode']!='error' && | |
| 			$this->url=$this->discover($proxy)) { | |
| 			$this->args['mode']='check_authentication'; | |
| 			$var=[]; | |
| 			foreach ($this->args as $key=>$val) | |
| 				$var['openid.'.$key]=$val; | |
| 			$req=\Web::instance()->request( | |
| 				$this->url, | |
| 				[ | |
| 					'method'=>'POST', | |
| 					'content'=>http_build_query($var), | |
| 					'proxy'=>$proxy | |
| 				] | |
| 			); | |
| 			return (bool)preg_match('/is_valid:true/i',$req['body']); | |
| 		} | |
| 		return FALSE; | |
| 	} | |
| 
 | |
| 	/** | |
| 	*	Return OpenID response fields | |
| 	*	@return array | |
| 	**/ | |
| 	function response() { | |
| 		return $this->args; | |
| 	} | |
| 
 | |
| 	/** | |
| 	*	Return TRUE if OpenID request parameter exists | |
| 	*	@return bool | |
| 	*	@param $key string | |
| 	**/ | |
| 	function exists($key) { | |
| 		return isset($this->args[$key]); | |
| 	} | |
| 
 | |
| 	/** | |
| 	*	Bind value to OpenID request parameter | |
| 	*	@return string | |
| 	*	@param $key string | |
| 	*	@param $val string | |
| 	**/ | |
| 	function set($key,$val) { | |
| 		return $this->args[$key]=$val; | |
| 	} | |
| 
 | |
| 	/** | |
| 	*	Return value of OpenID request parameter | |
| 	*	@return mixed | |
| 	*	@param $key string | |
| 	**/ | |
| 	function &get($key) { | |
| 		if (isset($this->args[$key])) | |
| 			$val=&$this->args[$key]; | |
| 		else | |
| 			$val=NULL; | |
| 		return $val; | |
| 	} | |
| 
 | |
| 	/** | |
| 	*	Remove OpenID request parameter | |
| 	*	@return NULL | |
| 	*	@param $key | |
| 	**/ | |
| 	function clear($key) { | |
| 		unset($this->args[$key]); | |
| 	} | |
| 
 | |
| }
 | |
| 
 |