1<?php 2 3/** 4 * Class for representing a SAML 2 error. 5 * 6 * @package SimpleSAMLphp 7 */ 8class sspmod_saml_Error extends SimpleSAML_Error_Exception 9{ 10 /** 11 * The top-level status code. 12 * 13 * @var string 14 */ 15 private $status; 16 17 /** 18 * The second-level status code, or NULL if no second-level status code is defined. 19 * 20 * @var string|null 21 */ 22 private $subStatus; 23 24 /** 25 * The status message, or NULL if no status message is defined. 26 * 27 * @var string|null 28 */ 29 private $statusMessage; 30 31 32 /** 33 * Create a SAML 2 error. 34 * 35 * @param string $status The top-level status code. 36 * @param string|null $subStatus The second-level status code. Can be NULL, in which case there is no second-level status code. 37 * @param string|null $statusMessage The status message. Can be NULL, in which case there is no status message. 38 * @param Exception|null $cause The cause of this exception. Can be NULL. 39 */ 40 public function __construct($status, $subStatus = null, $statusMessage = null, Exception $cause = null) 41 { 42 assert(is_string($status)); 43 assert($subStatus === null || is_string($subStatus)); 44 assert($statusMessage === null || is_string($statusMessage)); 45 46 $st = self::shortStatus($status); 47 if ($subStatus !== null) { 48 $st .= '/' . self::shortStatus($subStatus); 49 } 50 if ($statusMessage !== null) { 51 $st .= ': ' . $statusMessage; 52 } 53 parent::__construct($st, 0, $cause); 54 55 $this->status = $status; 56 $this->subStatus = $subStatus; 57 $this->statusMessage = $statusMessage; 58 } 59 60 61 /** 62 * Get the top-level status code. 63 * 64 * @return string The top-level status code. 65 */ 66 public function getStatus() 67 { 68 return $this->status; 69 } 70 71 72 /** 73 * Get the second-level status code. 74 * 75 * @return string|null The second-level status code or NULL if no second-level status code is present. 76 */ 77 public function getSubStatus() 78 { 79 return $this->subStatus; 80 } 81 82 83 /** 84 * Get the status message. 85 * 86 * @return string|null The status message or NULL if no status message is present. 87 */ 88 public function getStatusMessage() 89 { 90 return $this->statusMessage; 91 } 92 93 94 /** 95 * Create a SAML2 error from an exception. 96 * 97 * This function attempts to create a SAML2 error with the appropriate 98 * status codes from an arbitrary exception. 99 * 100 * @param Exception $exception The original exception. 101 * @return sspmod_saml_Error The new exception. 102 */ 103 public static function fromException(Exception $exception) 104 { 105 if ($exception instanceof sspmod_saml_Error) { 106 // Return the original exception unchanged 107 return $exception; 108 109 // TODO: remove this branch in 2.0 110 } elseif ($exception instanceof SimpleSAML_Error_NoPassive) { 111 $e = new self( 112 \SAML2\Constants::STATUS_RESPONDER, 113 \SAML2\Constants::STATUS_NO_PASSIVE, 114 $exception->getMessage(), 115 $exception 116 ); 117 // TODO: remove this branch in 2.0 118 } elseif ($exception instanceof SimpleSAML_Error_ProxyCountExceeded) { 119 $e = new self( 120 \SAML2\Constants::STATUS_RESPONDER, 121 \SAML2\Constants::STATUS_PROXY_COUNT_EXCEEDED, 122 $exception->getMessage(), 123 $exception 124 ); 125 } else { 126 $e = new self( 127 \SAML2\Constants::STATUS_RESPONDER, 128 null, 129 get_class($exception) . ': ' . $exception->getMessage(), 130 $exception 131 ); 132 } 133 134 return $e; 135 } 136 137 138 /** 139 * Create a normal exception from a SAML2 error. 140 * 141 * This function attempts to reverse the operation of the fromException() function. 142 * If it is unable to create a more specific exception, it will return the current 143 * object. 144 * 145 * @see sspmod_saml_Error::fromException() 146 * 147 * @return SimpleSAML_Error_Exception An exception representing this error. 148 */ 149 public function toException() 150 { 151 $e = null; 152 153 switch ($this->status) { 154 case \SAML2\Constants::STATUS_RESPONDER: 155 switch ($this->subStatus) { 156 case \SAML2\Constants::STATUS_NO_PASSIVE: 157 $e = new SimpleSAML\Module\saml\Error\NoPassive( 158 \SAML2\Constants::STATUS_RESPONDER, 159 $this->statusMessage 160 ); 161 break; 162 } 163 break; 164 } 165 166 if ($e === null) { 167 return $this; 168 } 169 170 return $e; 171 } 172 173 174 /** 175 * Create a short version of the status code. 176 * 177 * Remove the 'urn:oasis:names:tc:SAML:2.0:status:'-prefix of status codes 178 * if it is present. 179 * 180 * @param string $status The status code. 181 * @return string A shorter version of the status code. 182 */ 183 private static function shortStatus($status) 184 { 185 assert(is_string($status)); 186 187 $t = 'urn:oasis:names:tc:SAML:2.0:status:'; 188 if (substr($status, 0, strlen($t)) === $t) { 189 return substr($status, strlen($t)); 190 } 191 192 return $status; 193 } 194} 195