An embedded application on a Synology NAS is not automatically protected from accessing it without being logged in to DSM. Luckily Synology has an authentication mechanism, Web Authentication, described in their Developers guide. This enables you application to detect whether a user is logged in to DSM. Getting this to work for PHP is not that difficult, but you will encounter a few bumps on the road.
SynoToken
To get the current username from Synology’s authenticate.cgi script you need a SynoToken. This token can be acquired by executing /usr/syno/synoman/webman/login.cgi
, which returns an HTTP response containing a body of JSON. The function shell_exec()
can be used to call this script. This script may generate some warnings, so it’s a good idea to prevent anything written to stderr in the output by using 2>/dev/null
:
$response = shell_exec('/usr/syno/synoman/webman/login.cgi 2>/dev/null'); echo $response;
Content-type: text/html; charset="UTF-8" P3P: CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT" { "SynoToken" : "yFMVWrVDZXwz5", "result" : "success", "success" : true }
To get the token the most elegant way is to parse the HTTP response and then parse the JSON in the body.
Update Dec 20, 2014: Fetching the SynoToken seems only necessary in early versions of DSM 5.0.
Authenticate
The script /usr/syno/synoman/webman/modules/authenticate.cgi
returns the username of the user logged in to DSM and expects the SynoToken in the GET parameters of the current request. An alternative for doing one request for the token and another one for the username is to alter the environment variable QUERY_STRING
before calling authenticate.cgi
:
// Update Update Dec 20, 2014: the next two lines are only necessary in early versions of DSM 5.0. $token = 'yFMVWrVDZXwz5'; putenv('QUERY_STRING=SynoToken=' . $token); $username = shell_exec('/usr/syno/synoman/webman/modules/authenticate.cgi'); echo $username;
Rob
Administrator?
To enable or disable certain functionality in your application, you might want to know whether a user is an administrator. A list of group ids a user is member of can be retrieved with the command id -G *username*
. If 101 is in it, the user is administrator. Make sure to escape the username.
$username = "admin"; $groups = shell_exec('id -G ' . escapeshellarg($username) . ' 2>/dev/null'); print_r(explode(' ', $groups));
Array ( [0] => 100 [1] => 25 [2] => 101 )
Logging in
Update Dec 20, 2014: I’ve written this paragraph after a question about logging in.
To log in, the user simply uses the homepage of DSM. But it’s also possible to build your own log in form by executing /usr/syno/synoman/webman/login.cgi
. The username and password must be set in the environment variable QUERY_STRING
for this to work:
putenv('QUERY_STRING=username=admin&passwd=secret'); $result = shell_exec('/usr/syno/synoman/webman/login.cgi');
Content-Type: text/html; charset="UTF-8" P3P: CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT" Set-Cookie: id=8b9EKhZnb3w1YC4KNN00020;path=/ { "result" : "success", "success" : true }
If the Set-Cookie
header is forwarded to the client, then the user is authenticated starting the next request. It’s possible for the user to be authenticated immediately, by adding cookie value id
in the Set-Cookie
header to the cookie values in the environment variable HTTP_COOKIE
:
$httpCookie = getenv('HTTP_COOKIE') . '; id=8b9EKhZnb3w1YC4KNN00020'); putenv('HTTP_COOKIE=' . $httpCookie);
Composer package
I’ve created a Composer package on GitHub you can use to authenticate. This is tested on DSM 4 and 5.1.
$core = new \ultimo\sdk\synology\ds\Core(); // get details of the user currently logged in to DSM $username = $core->authenticate(); $userId = $core->getUserId($username); $groups = $core->getUserGroupIds($username); // log in as admin if ($core->login("AdMiN", "secret")) { echo "Now logged in as " . $core->authenticate(); }
December 18, 2014 at 12:40 am
Hi Rob !
Thanks for your jobs and your blog !! So interresting !! 🙂
Sorry in advance if my question seem somehow “newbie like” :
How could you integrate your authentification script in simple web page ? My goal is to make one single authentification web page to permit my web user to log on the website :-).
Thanks in advance !!
JPC
December 18, 2014 at 8:32 am
This authentication method uses the mechanism of the Diskstation itself. You can retrieve the username or id of the user logged to DSM, which is useful for embedded PHP apps on a Synology NAS. This way you don’t need a login page, but each user must be created within DSM.
If you host a PHP website unrelated to a Synology NAS, then use a traditional login mechanism. The basic principles are explained on many webpages, e.g. here.
December 18, 2014 at 10:39 am
Thanks for your answer !
I see your point. In fact, I’m searching a way to log on a web site hosted on my Syno NAS but using the DSM’s User List & groups.
Maybe I have missed something, but I’m really surprise that mechanism doesn’t native on the Syno (a package ?) or that other person doesn’t already works on this point. Maybe it will be necessary to use a LDAP directory instead of the DSM Directory ?
regards,
JPC
December 18, 2014 at 11:59 am
That’s an interesting question. The Developers guide only speaks about a mechanism to determine which used is logged in, but not about a method to log on a user.
The DSM home screen logs on using two POST request. First it asks a cipher key to
/webapi/encryption.cgi
to encrypt the credentials. Then those are sent to/login.cgi
to log on. This returns a JSON response that contains whether the log on was successful. Your custom log on form could do the same.Authentication to DSM for your website means that those users have access to DSM, unless you protect it some other way.
December 19, 2014 at 4:22 pm
Thanks for your answer and hints ;-). I’ll keep going searching on these different way !
Best regards,
JPC
December 20, 2014 at 8:19 pm
I’ve done a little research and found a way to log in to DSM using PHP. I’ve updated the Composer package and this blog post with the results.
February 6, 2015 at 3:05 pm
Thanks again ! 🙂 I’ll check that soon !!
Have a nice new year !! 😉
JPC