]> CyberLeo.Net >> Repos - Github/YOURLS.git/blob - includes/functions-auth.php
Support for salted encrypted passwords. See issues 755 & 875.
[Github/YOURLS.git] / includes / functions-auth.php
1 <?php\r
2 // Check for valid user. Returns true or an error message\r
3 function yourls_is_valid_user() {\r
4         static $valid = false;\r
5         \r
6         if( $valid )\r
7                 return true;\r
8 \r
9         // Logout request\r
10         if( isset( $_GET['action'] ) && $_GET['action'] == 'logout') {\r
11                 yourls_store_cookie( null );\r
12                 return 'Logged out successfully';\r
13         }\r
14         \r
15         // Check cookies or login request. Login form has precedence.\r
16         global $yourls_user_passwords;\r
17         \r
18         // Determine auth method and check credentials\r
19         if\r
20                 // API only: Secure (no login or pwd) and time limited token\r
21                 // ?timestamp=12345678&signature=md5(totoblah12345678)\r
22                 ( yourls_is_API() &&\r
23                   isset($_REQUEST['timestamp']) && !empty($_REQUEST['timestamp']) &&\r
24                   isset($_REQUEST['signature']) && !empty($_REQUEST['signature'])\r
25                 )\r
26                 {\r
27                         $valid = yourls_check_signature_timestamp();\r
28                 }\r
29                 \r
30         elseif\r
31                 // API only: Secure (no login or pwd)\r
32                 // ?signature=md5(totoblah)\r
33                 ( yourls_is_API() &&\r
34                   !isset($_REQUEST['timestamp']) &&\r
35                   isset($_REQUEST['signature']) && !empty($_REQUEST['signature'])\r
36                 )\r
37                 {\r
38                         $valid = yourls_check_signature();\r
39                 }\r
40         \r
41         elseif\r
42                 // API or normal: login with username & pwd\r
43                 ( isset($_REQUEST['username']) && isset($_REQUEST['password'])\r
44                   && !empty( $_REQUEST['username'] ) && !empty( $_REQUEST['password']  ) )\r
45                 {\r
46                         $valid = yourls_check_username_password();\r
47                 }\r
48         \r
49         elseif\r
50                 // Normal only: cookies\r
51                 ( !yourls_is_API() && \r
52                   isset($_COOKIE['yourls_username']) && isset($_COOKIE['yourls_password']) )\r
53                 {\r
54                         $valid = yourls_check_auth_cookie();\r
55                 }\r
56 \r
57         // Login for the win!\r
58         if ( $valid ) {\r
59                 // (Re)store encrypted cookie and tell it's ok\r
60                 if ( !yourls_is_API() ) // No need to store a cookie when used in API mode.\r
61                         yourls_store_cookie( YOURLS_USER );\r
62                 return true;\r
63         }\r
64         \r
65         // Login failed\r
66         if ( isset($_REQUEST['username']) || isset($_REQUEST['password']) ) {\r
67                 return 'Invalid username or password';\r
68         } else {\r
69                 return 'Please log in';\r
70         }\r
71 }\r
72 \r
73 // Check auth against list of login=>pwd. Sets user if applicable, returns bool\r
74 function yourls_check_username_password() {\r
75         global $yourls_user_passwords;\r
76         if( isset( $yourls_user_passwords[ $_REQUEST['username'] ] ) && yourls_check_password_hash( $yourls_user_passwords[ $_REQUEST['username'] ], $_REQUEST['password'] ) ) {\r
77                 yourls_set_user( $_REQUEST['username'] );\r
78                 return true;\r
79         }\r
80         return false;\r
81 }\r
82 \r
83 // Check a REQUEST password sent in plain text against stored password which can be a salted hash\r
84 function yourls_check_password_hash( $stored, $plaintext ) {\r
85         if ( substr( $stored, 0, 4 ) == 'md5:' and strlen( $stored ) == 42 ) {\r
86                 // Stored password is a salted hash: "md5:<$r = rand(10000,99999)>:<md5($r.'thepassword')>"\r
87                 // And 42. Of course. http://www.google.com/search?q=the+answer+to+life+the+universe+and+everything\r
88                 list( $temp, $salt, $md5 ) = split( ':', $stored );\r
89                 return( $stored == 'md5:'.$salt.':'.md5( $salt.$plaintext ) );\r
90         } else {\r
91                 // Password was sent in clear\r
92                 return( $stored == $plaintext );\r
93         }\r
94 }\r
95 \r
96 \r
97 // Check auth against encrypted COOKIE data. Sets user if applicable, returns bool\r
98 function yourls_check_auth_cookie() {\r
99         global $yourls_user_passwords;\r
100         foreach( $yourls_user_passwords as $valid_user => $valid_password ) {\r
101                 if( \r
102                         yourls_salt($valid_user) == $_COOKIE['yourls_username']\r
103                         && yourls_salt($valid_password) == $_COOKIE['yourls_password'] \r
104                 ) {\r
105                         yourls_set_user( $valid_user );\r
106                         return true;\r
107                 }\r
108         }\r
109         return false;\r
110 }\r
111 \r
112 // Check auth against signature and timestamp. Sets user if applicable, returns bool\r
113 function yourls_check_signature_timestamp() {\r
114         // Timestamp in PHP : time()\r
115         // Timestamp in JS: parseInt(new Date().getTime() / 1000)\r
116         global $yourls_user_passwords;\r
117         foreach( $yourls_user_passwords as $valid_user => $valid_password ) {\r
118                 if (\r
119                         (\r
120                                 md5( $_REQUEST['timestamp'].yourls_auth_signature( $valid_user ) ) == $_REQUEST['signature']\r
121                                 or\r
122                                 md5( yourls_auth_signature( $valid_user ).$_REQUEST['timestamp'] ) == $_REQUEST['signature']\r
123                         )\r
124                         &&\r
125                         yourls_check_timestamp( $_REQUEST['timestamp'] )\r
126                         ) {\r
127                         yourls_set_user( $valid_user );\r
128                         return true;\r
129                 }\r
130         }\r
131         return false;\r
132 }\r
133 \r
134 // Check auth against signature. Sets user if applicable, returns bool\r
135 function yourls_check_signature() {\r
136         global $yourls_user_passwords;\r
137         foreach( $yourls_user_passwords as $valid_user => $valid_password ) {\r
138                 if ( yourls_auth_signature( $valid_user ) == $_REQUEST['signature'] ) {\r
139                         yourls_set_user( $valid_user );\r
140                         return true;\r
141                 }\r
142         }\r
143         return false;\r
144 }\r
145 \r
146 // Generate secret signature hash\r
147 function yourls_auth_signature( $username = false ) {\r
148         if( !$username && defined('YOURLS_USER') ) {\r
149                 $username = YOURLS_USER;\r
150         }\r
151         return ( $username ? substr( yourls_salt( $username ), 0, 10 ) : 'Cannot generate auth signature: no username' );\r
152 }\r
153 \r
154 // Check a timestamp is from the past and not too old\r
155 function yourls_check_timestamp( $time ) {\r
156         $now = time();\r
157         return ( $now >= $time && ceil( $now - $time ) < YOURLS_NONCE_LIFE );\r
158 }\r
159 \r
160 // Store new cookie. No $user will delete the cookie.\r
161 function yourls_store_cookie( $user = null ) {\r
162         if( !$user ) {\r
163                 $pass = null;\r
164                 $time = time() - 3600;\r
165         } else {\r
166                 global $yourls_user_passwords;\r
167                 if( isset($yourls_user_passwords[$user]) ) {\r
168                         $pass = $yourls_user_passwords[$user];\r
169                 } else {\r
170                         die('Stealing cookies?'); // This should never happen\r
171                 }\r
172                 $time = time() + YOURLS_COOKIE_LIFE;\r
173         }\r
174         \r
175         $domain   = yourls_apply_filter( 'setcookie_domain',   parse_url( YOURLS_SITE, 1 ) );\r
176         $secure   = yourls_apply_filter( 'setcookie_secure',   yourls_is_ssl() );\r
177         $httponly = yourls_apply_filter( 'setcookie_httponly', true );\r
178                 \r
179         if ( !headers_sent() ) {\r
180                 // Set httponly if the php version is >= 5.2.0\r
181                 if( version_compare( phpversion(), '5.2.0', 'ge' ) ) {\r
182                         setcookie('yourls_username', yourls_salt( $user ), $time, '/', $domain, $secure, $httponly );\r
183                         setcookie('yourls_password', yourls_salt( $pass ), $time, '/', $domain, $secure, $httponly );\r
184                 } else {\r
185                         setcookie('yourls_username', yourls_salt( $user ), $time, '/', $domain, $secure );\r
186                         setcookie('yourls_password', yourls_salt( $pass ), $time, '/', $domain, $secure );\r
187                 }\r
188         }\r
189 }\r
190 \r
191 // Set user name\r
192 function yourls_set_user( $user ) {\r
193         if( !defined('YOURLS_USER') )\r
194                 define('YOURLS_USER', $user);\r
195 }\r