Example #1
0
 /**
  * Authenticates the OAuth client.
  *
  * This function detects whether credentials for an OAuth client is
  * presented in the `Authorization` header or the POST body.
  */
 public function initClient()
 {
     $this->logger->log(LogLevel::DEBUG, 'SimpleID\\Protocols\\OAuth\\OAuthManager->initClient');
     $store = StoreManager::instance();
     $request = new Request();
     $header = $request->getAuthorizationHeader(true);
     if ($header != null && $header['#scheme'] == 'Basic') {
         $client_auth_method = 'client_secret_basic';
         $client_id = $header['#username'];
         $client_secret = $header['#password'];
     }
     if (!$client_id && $this->f3->exists('POST.client_id') && $this->f3->exists('POST.client_secret')) {
         $client_auth_method = 'client_secret_post';
         $client_id = $this->f3->get('POST.client_id');
         $client_secret = $this->f3->get('POST.client_secret');
     }
     if ($client_id) {
         $client = $store->loadClient($client_id, 'SimpleID\\Protocols\\OAuth\\OAuthClient');
         if ($client['oauth']['client_secret'] != $client_secret) {
             return;
         }
         $this->client_auth_method = $client_auth_method;
     } else {
         $results = $this->mgr->invokeAll('oAuthInitClient', $request);
         $results = array_merge(array_diff($results, array(NULL)));
         if (count($results) == 1) {
             $client = $results[0]['#client'];
             $this->client_auth_method = $results[0]['#client_auth_method'];
         }
     }
     $this->f3->set('oauth_client', $client);
     $this->logger->log(LogLevel::INFO, 'OAuth client: ' . $client_id . ' [' . $this->client_auth_method . ']');
 }
 /**
  * Returns the user's OpenID 2.0 verification page.
  *
  * @see SimpleID\Base\UserModule::user()
  */
 public function userJSON($f3, $params)
 {
     $mgr = ModuleManager::instance();
     $iss = $mgr->getModule('SimpleID\\Protocols\\Connect\\ConnectModule')->getCanonicalHost();
     $store = StoreManager::instance();
     $user = $store->loadUser($params['uid']);
     if ($user != NULL) {
         header('Content-Type: application/json');
         print json_encode(array('iss' => $iss));
     } else {
         $this->f3->status(404);
         $this->fatalError($this->t('User %uid not found.', array('%uid' => $uid)));
     }
 }
Example #3
0
 /**
  * Attempts to automatically login using the client certificate
  * 
  * @return SimpleID\Models\User the user object, or NULL
  */
 public function autoAuthHook()
 {
     if (!$this->hasClientCert()) {
         return NULL;
     }
     $cert = trim($_SERVER['SSL_CLIENT_M_SERIAL']) . ';' . trim($_SERVER['SSL_CLIENT_I_DN']);
     $this->logger->log(LogLevel::DEBUG, 'Client SSL certificate: ' . $cert);
     $store = StoreManager::instance();
     $user = $store->findUser('cert.certs', $cert);
     if ($user != NULL) {
         $this->logger->log(LogLevel::DEBUG, 'Client SSL certificate accepted for ' . $user['uid']);
         return $user;
     } else {
         $this->logger->log(LogLevel::DEBUG, 'Client SSL certificate presented, but no user with that certificate exists.');
         return NULL;
     }
 }
 /**
  * Attempts to automatically login using the auto login cookie
  * 
  * @see SimpleID\API\AuthHooks::autoAuthHook()
  * @return SimpleID\Models\User the user object, or NULL
  */
 public function autoAuthHook()
 {
     if (!$this->f3->exists('COOKIE.' . $this->cookie_name)) {
         return null;
     }
     $cookie = $this->f3->get('COOKIE.' . $this->cookie_name);
     $token = new SecurityToken();
     $data = $token->getPayload($cookie);
     if ($data === null) {
         $this->logger->log(LogLevel::NOTICE, 'Automatic login: Invalid token - clearing');
         $this->logoutHook();
         return null;
     }
     if ($data['typ'] != 'rememberme') {
         return NULL;
     }
     $this->logger->log(LogLevel::DEBUG, 'Automatic login token detected', $data);
     if ($data['exp'] < time()) {
         // Cookie expired
         $this->logger->log(LogLevel::NOTICE, 'Automatic login: Expired - clearing');
         $this->logoutHook();
         return NULL;
     }
     if ($data['uaid'] != $this->auth->assignUAID()) {
         $this->logger->log(LogLevel::WARNING, 'Automatic login: User agent ID does not match - clearing');
         $this->logoutHook();
         return NULL;
     }
     $store = StoreManager::instance();
     // Load the user, tag it as an auto log in
     $test_user = $store->loadUser($data['uid']);
     if ($test_user != NULL) {
         $this->logger->log(LogLevel::INFO, 'Automatic login token accepted for ' . $data['uid']);
         return $test_user;
     } else {
         $this->logger->log(LogLevel::WARNING, 'Automatic login token accepted for ' . $data['uid'] . ', but no such user exists');
         return NULL;
     }
 }
Example #5
0
 /**
  * Returns the user's public page.
  * 
  * @param string $uid the user ID
  */
 function user($f3, $params)
 {
     $web = \Web::instance();
     $tpl = \Template::instance();
     $store = StoreManager::instance();
     $mgr = ModuleManager::instance();
     $this->f3->set('title', $this->t('User Page'));
     if (!isset($params['uid'])) {
         $this->f3->status(400);
         $this->f3->set('message', $this->t('No user specified.'));
     } else {
         $user = $store->loadUser($params['uid']);
         if ($user == NULL) {
             $this->f3->status(404);
             $this->f3->set('message', $this->t('User %uid not found.', array('%uid' => $params['uid'])));
         } else {
             header('Vary: Accept');
             $content_type = $web->acceptable(array('text/html', 'application/xml', 'application/xhtml+xml', 'application/xrds+xml', 'application/json'));
             if ($content_type == 'application/xrds+xml' && $mgr->isModuleLoaded('SimpleID\\Protocols\\OpenID\\OpenIDModule')) {
                 $mgr->getModule('SimpleID\\Protocols\\OpenID\\OpenIDModule')->userXRDS($f3, $params);
                 return;
             } elseif ($content_type == 'application/json' && $mgr->isModuleLoaded('SimpleID\\Protocols\\Connect\\OpenID2MigrationModule')) {
                 $mgr->getModule('SimpleID\\Protocols\\Connect\\OpenID2MigrationModule')->userJSON($f3, $params);
             } else {
                 $xrds_location = $this->getCanonicalURL('@openid_user_xrds');
                 header('X-XRDS-Location: ' . $xrds_location);
                 $this->f3->set('message', $this->t('This is the user %uid\'s SimpleID page.  It contains hidden information for the use by OpenID consumers.', array('%uid' => $params['uid'])));
                 $this->f3->set('title', $user['uid']);
                 $this->f3->set('xrds', $xrds_location);
                 if ($user->hasLocalOpenIDIdentity()) {
                     $this->f3->set('local_id', $user["identity"]);
                 }
                 $this->f3->set('head', 'openid_head.html');
             }
         }
     }
     print $tpl->render('page.html');
 }
Example #6
0
 /**
  * Gets the site-specific encryption and signing key.
  *
  * If the key does not exist, it is automatically generated.
  *
  * @return string the site-specific encryption and signing key
  * as a base64url encoded string
  */
 protected static function getKey()
 {
     $store = StoreManager::instance();
     $key = $store->getSetting('oauth-fernet');
     if ($key == NULL) {
         $rand = new Random();
         $key = Fernet::base64url_encode($rand->bytes(32));
         $store->setSetting('oauth-fernet', $key);
     }
     return $key;
 }
Example #7
0
 /**
  * Returns the OAuth authorization that generated this code.
  *
  * If the authorization has been revoked, or is otherwise invalid, since
  * the authorization code has been issued, this function will return
  * `null`.
  *
  * @return Authorization the OAuth authorization or `null`.
  */
 public function getAuthorization()
 {
     $store = StoreManager::instance();
     $authorization = $store->loadAuth($this->aid);
     if ($authorization == null) {
         return null;
     }
     if ($authorization->getAuthState() != $this->auth_state) {
         return null;
     }
     return $authorization;
 }
Example #8
0
 /**
  * Creates an instance of the store module.
  *
  * The default constructor registers the store module with the
  * store manager by calling {@link StoreManager::addStore()}.
  */
 public function __construct()
 {
     parent::__construct();
     $store_manager = StoreManager::instance();
     $store_manager->addStore($this, $this->getStores());
 }
 /**
  * Verifies a set of credentials using the default user name-password authentication
  * method.
  *
  * @param string $uid the name of the user to verify
  * @param array $credentials the credentials supplied by the browser
  * @return bool whether the credentials supplied matches those for the specified
  * user
  */
 protected function verifyCredentials($uid, $credentials)
 {
     $store = StoreManager::instance();
     $test_user = $store->loadUser($uid);
     if ($test_user == NULL) {
         return false;
     }
     list($dummy, $prefix, $content) = explode('$', $test_user['password']['password'], 3);
     if ($prefix == null) {
         return false;
     }
     switch ($prefix) {
         case '2y':
             $bcrypt = Bcrypt::instance();
             return $bcrypt->verify($credentials['password']['password'], $test_user['password']['password']);
             break;
         case 'pbkdf2':
             $params = array();
             list($param_string, $hash, $salt) = explode('$', $content, 3);
             parse_str($param_string, $params);
             if (!isset($params['f'])) {
                 $params['f'] = 'sha256';
             }
             if (!isset($params['dk'])) {
                 $params['dk'] = 0;
             }
             return $this->secureCompare(PBKDF2::hash($params['f'], $credentials['password']['password'], base64_decode($salt), $params['c'], $params['dk'], true), base64_decode($hash));
             break;
         default:
             $this->logger->log(LogLevel::WARNING, 'Unknown password prefix: ' . $prefix);
             return false;
     }
 }
Example #10
0
 /**
  * Sets the current version of SimpleID.
  *
  * This function sets the version application setting via {@link \SimpleID\Store\StoreManager::setSetting()}.
  * A specific version can be specified, or it can be taken from {@link SIMPLEID_VERSION}.
  *
  * @param string $version the version to set
  */
 public function setVersion($version = NULL)
 {
     $store = StoreManager::instance();
     if ($version == NULL) {
         $version = SIMPLEID_VERSION;
     }
     $store->setSetting('version', $version);
 }
 /**
  * Configuration endpoint
  */
 public function get()
 {
     $this->checkHttps('error');
     $client_id = $this->f3->get('PARAMS.client_id');
     if (!$this->isAuthorized(self::CLIENT_REGISTRATION_ACCESS_SCOPE) || $this->getAccessToken()->getAuthorization()->getClient()->getStoreID() != $client_id) {
         $this->unauthorizedError('invalid_token');
         return;
     }
     $store = StoreManager::instance();
     $client = $store->loadClient($client_id);
     if ($client == NULL || !is_a($client, 'SimpleID\\Protocols\\Connect\\ConnectDynamicClient')) {
         $this->f3->status(404);
         $this->fatalError($this->t('Client not found.'));
         return;
     }
     header('Content-Type: application/json');
     header('Content-Disposition: inline');
     print json_encode($client->getDynamicClientInfo());
 }
Example #12
0
 /**
  * Gets the site-specific encryption and signing key.
  *
  * If the key does not exist, it is automatically generated.
  *
  * @return string the site-specific encryption and signing key
  * as a base64url encoded string
  */
 private static function getSiteToken()
 {
     $store = StoreManager::instance();
     $site_token = $store->getSetting('site-token');
     if ($site_token == NULL) {
         $rand = new Random();
         $site_token = Fernet::base64url_encode($rand->bytes(32));
         $store->setSetting('site-token', $site_token);
     }
     return $site_token;
 }
Example #13
0
 /**
  * @see SimpleID\API\OAuthHooks::oAuthGrantAuthHook()
  */
 function oAuthGrantAuthHook($authorization, $request, $response, $scopes)
 {
     // code: ?code / id_token
     // id_token: #id_token
     // id_token token: #access_token #id_token
     // code id_token: #code #id_token[c_hash] / id_token
     // code token: #code #access_token / id_token
     // code id_token token: #code #access_token #id_token[c_hash, at_hash] / id_token
     if ($request->paramContains('scope', 'openid')) {
         $user = AuthManager::instance()->getUser();
         $client = StoreManager::instance()->loadClient($request['client_id'], 'SimpleID\\Protocols\\OAuth\\OAuthClient');
         if (isset($request['claims']) && is_string($request['claims'])) {
             $request['claims'] = json_decode($request['claims'], true);
         }
         // 1. Build claims
         $claims_requested = isset($request['claims']['id_token']) ? $request['claims']['id_token'] : null;
         $claims = $this->buildClaims($user, $client, 'id_token', $scopes, $claims_requested);
         if (isset($request['nonce'])) {
             $claims['nonce'] = $request['nonce'];
         }
         // 2. Encode claims as jwt
         if ($request->paramContains('response_type', 'id_token')) {
             // response_type = id_token, code id_token, id_token token, code id_token token
             // Response is always fragment
             $response->setResponseMode(Response::FRAGMENT_RESPONSE_MODE);
             // Build authorisation response ID token
             $jose = new JOSEResponse($this->getCanonicalHost(), $client, 'connect.id_token', $claims, 'RS256');
             if (isset($response['code'])) {
                 $jose->setShortHashClaim('c_hash', $response['code']);
             }
             if (isset($response['access_token'])) {
                 $jose->setShortHashClaim('at_hash', $response['access_token']);
             }
             $response['id_token'] = $jose->buildJOSE();
         }
         if ($request->paramContains('response_type', 'code')) {
             // response_type = code, code token
             // Save the id token for token endpoint
             $authorization->additional['id_token_claims'] = $claims;
         }
         // Note response_type = token is not defined
         // 3. Save claims for UserInfo endpoint
         if (isset($request['claims'])) {
             $authorization->additional['claims'] = $request['claims'];
         }
     }
 }
Example #14
0
 /**
  * Returns the user's public XRDS page.
  */
 public function userXRDS($f3, $params)
 {
     $store = StoreManager::instance();
     $user = $store->loadUser($params['uid']);
     if ($user != NULL) {
         $tpl = new \Template();
         if ($user->hasLocalOpenIDIdentity()) {
             $this->f3->set('local_id', $user["identity"]);
         }
         header('Content-Disposition: inline; filename=yadis.xml');
         print $tpl->render('openid_user_xrds.xml', 'application/xrds+xml');
     } else {
         $this->f3->status(404);
         $this->fatalError($this->t('User %uid not found.', array('%uid' => $uid)));
     }
 }
Example #15
0
 /** @see SimpleID\API\MyHooks::revokeAppHook() */
 public function revokeAppHook($cid)
 {
     $auth = AuthManager::instance();
     $store = StoreManager::instance();
     $user = $auth->getUser();
     $client = $store->loadClient($cid, 'SimpleID\\Protocols\\OAuth\\OAuthClient');
     $aid = Authorization::buildID($user, $client);
     $authorization = $store->loadAuth($aid);
     if ($authorization != null) {
         $authorization->revokeAllTokens();
         $store->deleteAuth($authorization);
     }
 }
Example #16
0
 /**
  * Gets the site-specific key for generating identifiers.
  *
  * If the key does not exist, it is automatically generated.
  *
  * @return string site-specific key as a binary string
  */
 private static function getOpaqueToken()
 {
     $store = StoreManager::instance();
     $opaque_token = $store->getSetting('opaque-token');
     if ($opaque_token == NULL) {
         $rand = new Random();
         $opaque_token = $rand->bytes(16);
         $store->setSetting('opaque-token', base64_encode($opaque_token));
     } else {
         $opaque_token = base64_decode($opaque_token);
     }
     return $opaque_token;
 }
Example #17
0
 /**
  * @see SimpleID\API\AuthHooks::loginHook()
  */
 public function loginHook($user, $level, $modules, $form_state)
 {
     $auth = AuthManager::instance();
     $store = StoreManager::instance();
     if ($level >= AuthManager::AUTH_LEVEL_VERIFIED && isset($form_state['otp_remember']) && $form_state['otp_remember'] == 1) {
         $uaid = $auth->assignUAID();
         if (!isset($user->auth[$uaid])) {
             $user->auth[$uaid] = array();
         }
         if (!isset($user->auth[$uaid]['otp'])) {
             $user->auth[$uaid]['otp'] = array();
         }
         $user->auth[$uaid]['otp']['remember'] = true;
         $store->saveUser($user);
     }
 }
Example #18
0
 public function delete($f3, $params)
 {
     $this->checkHttps('error', true);
     parse_str($this->f3->get('BODY'), $delete);
     header('Content-Type: application/json');
     $token = new SecurityToken();
     if (!isset($delete['tk']) || !$token->verify($delete['tk'], 'apps')) {
         $this->f3->status(401);
         print json_encode(array('error' => 'unauthorized', 'error_description' => $this->t('Unauthorized')));
         return;
     }
     $auth = AuthManager::instance();
     $user = $auth->getUser();
     $prefs =& $user->clients;
     if (!isset($prefs[$params['cid']])) {
         $this->f3->status(404);
         print json_encode(array('error' => 'not_found', 'error_description' => $this->t('Not found')));
         return;
     }
     $mgr = ModuleManager::instance();
     $mgr->invokeAll('revokeApp', $params['cid']);
     unset($prefs[$params['cid']]);
     $store = StoreManager::instance();
     $store->saveUser($user);
     print json_encode(array('result' => 'success', 'result_description' => $this->t('App has been deleted.')));
 }
Example #19
0
 /**
  * Returns a Storable object based on a reference.
  *
  * A reference of a Storable object is its store type (from 
  * {@link SimpleID\Store\Storable::getStoreType()}) and its ID (from
  * {@link SimpleID\Store\Storable::getStoreID()}), separated by a colon.
  *
  * @param string $ref the reference to the storable object
  * @param array $args additional parameters
  * @return Storable the storable object or null
  */
 protected function getStorable($ref, $args = array())
 {
     $store = StoreManager::instance();
     $f3 = \Base::instance();
     list($type, $id) = explode(':', $ref, 2);
     array_unshift($args, $id);
     return call_user_func_array(array($store, 'load' . ucfirst($f3->camelCase($type))), $args);
 }
Example #20
0
 /**
  * Creates a JRD document based on a SimpleID user.
  *
  * The JRD document created is very simple - it merely points to the
  * SimpleID installation as the OpenID connect provider.
  *
  * @param array $resource the resource identifier
  * @return array the JRD document
  */
 protected function getJRD($resource)
 {
     $store = StoreManager::instance();
     $criteria = $this->getResourceCriteria($resource);
     if ($criteria == null) {
         return null;
     }
     foreach ($criteria as $criterion => $value) {
         $user = $store->findUser($criterion, $value);
         if ($user != null) {
             break;
         }
     }
     if ($user == null) {
         return null;
     }
     $jrd = array('subject' => $user['identity'], 'links' => array(array('rel' => 'http://specs.openid.net/auth/2.0/provider', 'href' => rtrim($this->f3->get('config.canonical_base_path'), '/')), array('rel' => 'http://openid.net/specs/connect/1.0/issuer', 'href' => rtrim($this->f3->get('config.canonical_base_path'), '/'))));
     if (isset($user['aliases'])) {
         if (is_array($user['aliases'])) {
             $jrd['aliases'] = $user['aliases'];
         } else {
             $jrd['aliases'] = array($user['aliases']);
         }
     }
     return $jrd;
 }
Example #21
0
 /**
  * Sets the user specified by the parameter as the active user.
  *
  * @param SimpleID\Models\User $user the user to log in
  * @param int $level the level of authentication achieved in this
  * session
  * @param array $modules array of authentication modules used to
  * authenticate the user in this session
  * @param array $form_state
  */
 public function login($user, $level, $modules = array(), $form_state = array())
 {
     $store = StoreManager::instance();
     if (is_string($user)) {
         $user = $store->loadUser($user);
     }
     $this->f3->set('user', $user);
     $this->auth_info['uid'] = $user['uid'];
     $this->auth_info['level'] = $level;
     $this->auth_info['modules'] = $modules;
     $this->auth_info['time'] = time();
     if ($level >= self::AUTH_LEVEL_AUTO) {
         $_SESSION['auth'] = $this->auth_info;
         $this->cache->set(rawurlencode($user['uid']) . '.login', session_id());
         $this->assignUALoginState(true);
     }
     if ($level > self::AUTH_LEVEL_AUTO) {
         if (!isset($form_state['auth_skip_activity'])) {
             $activity = array('type' => 'browser', 'level' => $level, 'modules' => $modules, 'time' => $_SESSION['auth']['time']);
             if ($this->f3->exists('IP')) {
                 $activity['remote'] = $this->f3->get('IP');
             }
             if ($this->f3->exists('HEADERS.User-Agent')) {
                 $activity['ua'] = $this->f3->get('HEADERS.User-Agent');
             }
             $user->addActivity($this->assignUAID(), $activity);
             $store->saveUser($user);
         }
         $this->logger->log(LogLevel::INFO, 'Login successful: ' . $user['uid']);
     }
     $this->mgr->invokeAll('login', $user, $level, $modules, $form_state);
 }