Jump to content

How to provide temporary access for external scripts?


johnstephens
 Share

Recommended Posts

Howdy,

I have a document created and served by ProcessWire. I want to make it visible only to someone who is logged in to ProcessWire OR to an external shell script being run by an authorized user.

I see how to designate authorized roles for access in the template's "Access" panel, and I see how to devise what content visitors can see in a page's template file using the API. Those cover the first scenario perfectly.

However, if I exclude "guests" (or any other roles) from accessing a page via the template's Access menu or via the API, that also prevents someone from getting the URL via a shell script.

I've solved this problem on other sites that use the Textpattern CMS, by adding the smd_access_keys plugin. The solution is twofold: The template or template section first detects whether an authentic user has privileges to view the page. If a privileged user is logged in, the template displays a special access URL that the user can use with their shell script. The URL access key has a built-in expiration, which prevents unauthorized access if someone somehow "guesses" the hash and salt at a later time.

One of my uses for this feature is to allow a managing editor to generate documents that can be converted to PDF using Prince XML. I have also used it to provide temporary access to web forms and other content. I might use it to give someone temporary access to a file hosted on the site, as per the plugin's documentation.

I'm not convinced that temporary access URLs is the only way or the best way to solve this problem, but I'm not sure how to do it at all using ProcessWire's API.

Do you know a way to allow temporary access to resources managed by ProcessWire to designated external services (like a shell script), without giving access to anyone who goes to the URL?

Thanks in advance!

Link to comment
Share on other sites

Hi,

Regarding the shell script, I assume you are talking about curl and the like? I don't know exactly - haven't tried specifically this, yet, but I think this could be roughly the right direction. (Just some thoughts about how I would probably approach this taking the script direction)

That page/template which handles the document could be an endpoint for a custom login-like GET request. In your shell script, promt for unsername and password and send them in the url parameters to that url via curl (using https these are encrypted). An additional parameter like “cli-document-request=1” could be handy to distinguish the different requests in your template. (web browser vs. curl). See if the login succeeds and deliver the contents of the file.

You have to look up the exact curl command by yourself, I don't use it that often :rolleyes: 
Random helpful stuff for inspiration:

download with curl: http://osxdaily.com/2014/02/13/download-with-curl/

curl: https://curl.haxx.se/docs/manpage.html

prompt for password, without echoing password: https://stackoverflow.com/questions/3980668/how-to-get-a-password-from-a-shell-script-without-echoing#3980904

https://askubuntu.com/questions/299870/http-post-and-get-using-curl-in-linux (aha, you can also “log in” with curl → I am sure there are even more advanced techniques using curl for a more proper authentication, but the above might be just fine.)

hope that was helpful :)

(If you have any more specific questions don't hesitate to ask)

best wishes
Steffen

  • Like 1
Link to comment
Share on other sites

1 hour ago, dragan said:

You could try like this: http://thisinterestsme.com/php-login-to-website-with-curl/

That doesn't work (would have been too easy). PW uses some hidden token field, for security reasons I guess, which changes on each request.

Yeah, that was my idea first, too. Then I remembered the token field. But you can force login a user with the other approach. I think in this case the token is not really useful since you have to authenticate manually on every request anyway.
The token is a prevention of CSRF attacks: https://de.wikipedia.org/wiki/Cross-Site-Request-Forgery. As I understand it correctly, it ensures that any potentially harmful request to the server is really made by you, the person using the website/app, and not someone else who might have tricked you to send a bad request. Any request is only executed if it includes the correct tokens.

@monchu

Mh, then it depends.

  • I would not recommend this approach, because you would have to put the credentials into the script, since you cannot (don't want to) ask for name and password every time. I guess putting plain text passwords into scripts is not so cool. ;P
    But yes, it is “possible”.
  • Otherwise, a simpler way would be to use a “supersecret-obfuscated-url”—while keeping in mind that this is just security by obscurity and in fact the url will be public. It might be just fine if the content is not “classified”-secret but just “it just should not be so easy to find”-secret. Make sure to exclude the pages from any sitemaps, etc. ...
  • If you have some admin/ssh access to the server you could use scp (scp?download file with scp) - using ssh authentication. 
  • Or any kind of secure command thing. sftp? Maybe even curl. Not sure ... I think it depends on what you want to achieve.

 

Btw. I would like to put a little disclaimer here, that I am by no means a security expert - these are just pieces of my humble knowledge and please regard all of it just as hints for further own research! :o Anyone with profound knowledge is invited to complement and/or correct :rolleyes:

  • Thanks 1
Link to comment
Share on other sites

15 hours ago, blynx said:

Otherwise, a simpler way would be to use a “supersecret-obfuscated-url”—while keeping in mind that this is just security by obscurity and in fact the url will be public. It might be just fine if the content is not “classified”-secret but just “it just should not be so easy to find”-secret. Make sure to exclude the pages from any sitemaps, etc. ...

Yes, that's what I'm doing. I use url segment with a long name in it. However, I just not comfortable with this solution.

Link to comment
Share on other sites

 

On 23/12/2017 at 1:44 AM, johnstephens said:

Do you know a way to allow temporary access to resources managed by ProcessWire to designated external services (like a shell script), without giving access to anyone who goes to the URL?

There is another idea I am using on the project I am working on.

Admitting its a PHP script :

  1. Put the script in a secure place on your server outside the public html
  2. Check if the script is run from CLI :  if(php_sapi_name() !== ‘cli’) mylog('unauthorized access from IP xxx...');
  3. Check the IP and allow only the script to be run from localhost: if($_SERVER['REMOTE_ADDR'] !== '127.0.0.1') mylog('unauthorized access from IP xxx...');
  4. Use a GET "sekret" variable and generate/update it each X time: if($_GET['sekret'] !== 'mysuperlongsekretkeyupdatedfromtimetotime') mylog('unauthorized access from IP xxx...');
  5. ForceLogin the user responsible to execute this job in PW and finalize the task

 

Hope it help.

  • Like 1
Link to comment
Share on other sites

  • 3 weeks later...

So one of my requirements is that the shell script that must access the secret content is executed on the editor's personal machine, not on the server. After scouring ProcessWire's API, I think I've stumbled upon a way to do the main thing I use smd_access_keys for:

function showSecretContent() {
  return "<pre>Secret content</pre>";
}

/**
 * Generate a key unique to this user and for this day only.
 */
$segment = sha1($user->name . $datetime->date('Y-m-d') . $this->config->userAuthSalt);

/**
 * Add the key to the URL for this page to use in links.
 */
$urlkey = $page->url . '?key=' . $segment;

/**
 * If there is a key in the URL request, save it.
 */
$key = $input->get('key');

/**
 * To authenticate the key for certified users only, save all users to an array.
 */
$allusers = $users->find('id>0');

/**
 * If the current session is logged in to ProcessWire, show the URL key and the secret content.
 */
if (!$user->isGuest()) {

  echo '<pre><a href="' . $urlkey . '">'. $urlkey . '</a>' .'</pre>';
  echo '<pre>This is what you will see:</pre>';

  echo showSecretContent();

} else {

  /**
   * If the page is accessed without a ProcessWire login, check if the key is set.
   */
  if (isset($key)) {

    /**
     * If the key is set, check all the users for a user who matches the key.
     */
    foreach ($allusers as $thatuser) {

      if ( $thatuser !== $users->getGuestUser() && $key == sha1( $thatuser->name . $datetime->date('Y-m-d') . $this->config->userAuthSalt ) ) {

        /**
         * If there is a user who matches the key, who isn't a "guest", show the secret content,
         * But only if the session isn't logged in.
         */  
        if ($user->isGuest()) echo showSecretContent();
      }

    }

  } else {

    /**
     * Don't show the secret content if the session isn't logged in or when the request doesn't include a key.
     */
    echo '<pre>Go away</pre>';
  }

}

Compared to smd_access_keys, this script does not allow keys to include custom expiration windows or expiration after a given number of requests—a "key" expires at midnight regardless of whether it was created at 00:01 or 11:59. This script also does not save keys to a database or allow keys to be voided in the ProcessWire admin. It also doesn't offer file protection. (smd_access_keys can be used to generate keyed links to download assets that you want to limit, like if you offer a MP3 or PDF download only to someone who signs up for your newsletter.)

But I didn't need those features for this implementation.

Can you see any problems with this approach? Are there security issues that I have overlooked? Are there any obvious improvements I should make?

Thanks for any guidance you can offer! I appreciate your comments and support.

  • Like 2
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...