1

I am planning to create a micropub plugin so that any micropub client can post to craft, particularly useful for automatic data logging and mobile clients. But I am trying to work out the best way to authenticate.

I have read through the UserIdentity docs but I was wondering if anybody has an examples of how to use it correctly?

  • I should note that micropub uses IndieAuth (similar to OpenID) and therefore the plugin will not have the password to authenticate with. – Shane Hudson Sep 24 '14 at 9:48
4

The basic user identity relies on login and password, so you will have to create your own class to represent an identity based on something else, like a token for example:

<?php

namespace Craft;

class TokenIdentity extends UserIdentity
{
    private $_id;
    public $token;

    public function __construct($token)
    {
        $this->token = $token;
    }

    public function authenticate()
    {
        $socialUser = craft()->social->getUserByEncodedToken($this->token);

        if($socialUser) {
            $this->_id = $socialUser->user->id;
            $this->username = $socialUser->user->username;
            $this->errorCode = static::ERROR_NONE;

            return true;
        } else {
            return false;
        }
    }

    public function getId()
    {
        return $this->_id;
    }
}

Then you'll need to create your own user session service to be able to authenticate the user (with a token for example):

<?php

namespace Craft;

class Social_UserSessionService extends UserSessionService {

    private $_identity;
    public $allowAutoLogin = true;

    public function init()
    {
        $this->setStateKeyPrefix(md5('Yii.Craft\UserSessionService.'.craft()->getId()));

        parent::init();
    }

    public function login(Oauth_TokenModel $token)
    {
        $rememberMe = true;

        $this->_identity = new TokenIdentity($token->encodedToken);
        $this->_identity->authenticate();

        // Was the login successful?
        if ($this->_identity->errorCode == TokenIdentity::ERROR_NONE)
        {
            // Get how long this session is supposed to last.

            $this->authTimeout = craft()->config->getUserSessionDuration($rememberMe);

            $id = $this->_identity->getId();

            $user = craft()->users->getUserById($id);

            $states = $this->_identity->getPersistentStates();


            // Run any before login logic.
            if ($this->beforeLogin($id, $states, false))
            {
                // Fire an 'onBeforeLogin' event
                $this->onBeforeLogin(new Event($this, array(
                    'username'      => $user->username,
                )));

                $this->changeIdentity($id, $this->_identity->getName(), $states);

                // Fire an 'onLogin' event
                $this->onLogin(new Event($this, array(
                    'username'      => $user->username,
                )));

                if ($this->authTimeout)
                {
                    if ($this->allowAutoLogin)
                    {
                        if ($user)
                        {
                            // Save the necessary info to the identity cookie.
                            $sessionToken = StringHelper::UUID();
                            $hashedToken = craft()->security->hashData(base64_encode(serialize($sessionToken)));
                            $uid = craft()->users->handleSuccessfulLogin($user, $hashedToken);

                            $data = array(
                                $this->getName(),
                                $sessionToken,
                                $uid,
                                ($rememberMe ? 1 : 0),
                                craft()->request->getUserAgent(),
                                $this->saveIdentityStates(),
                            );

                            $this->saveCookie('', $data, $this->authTimeout);
                        }
                        else
                        {
                            throw new Exception(Craft::t('Could not find a user with Id of {userId}.', array('{userId}' => $this->getId())));
                        }
                    }
                    else
                    {
                        throw new Exception(Craft::t('{class}.allowAutoLogin must be set true in order to use cookie-based authentication.', array('{class}' => get_class($this))));
                    }
                }

                $this->afterLogin(false);
            }

            return !$this->getIsGuest();
        }

        Craft::log('Tried to log in unsuccessfully.', LogLevel::Warning);
        return false;
    }
}

This code comes from a plugin which is still under development so don't take for granted it's all secure or the best way to achieve this, but hopefully it will help you get started !

  • I was planning to use tokens, so this looks like the perfect place to start. Thanks! – Shane Hudson Sep 24 '14 at 13:01
2

What about setting up a relation between your CustomUserAuthModel and the UserModel, check if everything is alright through your plugin with IndieAuth, and then login, through UserSessionService->impersonate()?

The new user session will only last as long as the browser session remains active; no identity cookie will be * created.

Not sure if that will work for you, but might be worth a try?

  • I didn't know about impersonate, that could be quite useful thanks! – Shane Hudson Sep 24 '14 at 13:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.