]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
OpenID access control options: trusted provider URL, Launchpad team restrictions...
authorBrion Vibber <brion@pobox.com>
Tue, 18 May 2010 17:39:56 +0000 (10:39 -0700)
committerBrion Vibber <brion@pobox.com>
Tue, 18 May 2010 20:28:41 +0000 (13:28 -0700)
To enable the admin panel:
    $config['admin']['panels'][] = 'openid';

Or to set them manually:
    $config['openid']['trusted_provider'] = 'https://login.ubuntu.net/';
    $config['openid']['required_team'] = 'my-project-cabal';
    $config['site']['openidonly'] = true;

OpenID-only mode can still be set from addPlugin() parameters as well for backwards compatibility.
Note: if it's set there, that value will override the setting from the database or config.php.

Note that team restrictions are only really meaningful if a trusted provider is set; otherwise,
any OpenID server could report back that users are members of the given team.

Restrictions are checked only at OpenID authentication time and will not kick off people currently
with a session open; existing remembered logins may also survive these changes.

Using code for Launchpad team support provided by Canonical under AGPLv3, pulled from r27 of
WordPress teams integration plugin:
    https://code.edge.launchpad.net/~canonical-isd-hackers/wordpress-teams-integration/trunk

plugins/OpenID/OpenIDPlugin.php
plugins/OpenID/extlib/README [new file with mode: 0644]
plugins/OpenID/extlib/teams-extension.php [new file with mode: 0644]
plugins/OpenID/finishaddopenid.php
plugins/OpenID/finishopenidlogin.php
plugins/OpenID/openid.php
plugins/OpenID/openidadminpanel.php [new file with mode: 0644]
plugins/OpenID/openidlogin.php
plugins/OpenID/openidsettings.php

index 270e2c624b57530f8e7376d39271cdcb00774cfa..9eac9f6fcd2b5ddace8100181e8f67cb0fbf0724 100644 (file)
@@ -20,7 +20,7 @@
  * @category  Plugin
  * @package   StatusNet
  * @author    Evan Prodromou <evan@status.net>
- * @copyright 2009 StatusNet, Inc.
+ * @copyright 2009-2010 StatusNet, Inc.
  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
  * @link      http://status.net/
  */
@@ -45,7 +45,19 @@ if (!defined('STATUSNET')) {
 
 class OpenIDPlugin extends Plugin
 {
-    public $openidOnly = false;
+    // Plugin parameter: set true to disallow non-OpenID logins
+    // If set, overrides the setting in database or $config['site']['openidonly']
+    public $openidOnly = null;
+
+    function initialize()
+    {
+        parent::initialize();
+        if ($this->openidOnly !== null) {
+            global $config;
+            $config['site']['openidonly'] = (bool)$this->openidOnly;
+        }
+
+    }
 
     /**
      * Add OpenID-related paths to the router table
@@ -67,6 +79,7 @@ class OpenIDPlugin extends Plugin
         $m->connect('index.php?action=finishaddopenid',
                     array('action' => 'finishaddopenid'));
         $m->connect('main/openidserver', array('action' => 'openidserver'));
+        $m->connect('admin/openid', array('action' => 'openidadminpanel'));
 
         return true;
     }
@@ -84,7 +97,7 @@ class OpenIDPlugin extends Plugin
 
     function onStartConnectPath(&$path, &$defaults, &$rules, &$result)
     {
-        if ($this->openidOnly) {
+        if (common_config('site', 'openidonly')) {
             static $block = array('main/login',
                                   'main/register',
                                   'main/recoverpassword',
@@ -108,7 +121,7 @@ class OpenIDPlugin extends Plugin
 
     function onArgsInitialize($args)
     {
-        if ($this->openidOnly) {
+        if (common_config('site', 'openidonly')) {
             if (array_key_exists('action', $args)) {
                 $action = trim($args['action']);
                 if (in_array($action, array('login', 'register'))) {
@@ -199,7 +212,7 @@ class OpenIDPlugin extends Plugin
 
     function onStartPrimaryNav($action)
     {
-        if ($this->openidOnly && !common_logged_in()) {
+        if (common_config('site', 'openidonly') && !common_logged_in()) {
             // TRANS: Tooltip for main menu option "Login"
             $tooltip = _m('TOOLTIP', 'Login to the site');
             // TRANS: Main menu option when not logged in to log in
@@ -241,7 +254,7 @@ class OpenIDPlugin extends Plugin
 
     function onStartLoginGroupNav(&$action)
     {
-        if ($this->openidOnly) {
+        if (common_config('site', 'openidonly')) {
             $this->showOpenIDLoginTab($action);
             // Even though we replace this code, we
             // DON'T run the End* hook, to keep others from
@@ -297,7 +310,7 @@ class OpenIDPlugin extends Plugin
      */
 
     function onStartAccountSettingsPasswordMenuItem($menu, &$unused) {
-        if ($this->openidOnly) {
+        if (common_config('site', 'openidonly')) {
             return false;
         }
         return true;
@@ -345,13 +358,19 @@ class OpenIDPlugin extends Plugin
         case 'OpenidsettingsAction':
         case 'OpenidserverAction':
         case 'OpenidtrustAction':
-            require_once INSTALLDIR.'/plugins/OpenID/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
+        case 'OpenidadminpanelAction':
+            require_once dirname(__FILE__) . '/' . strtolower(mb_substr($cls, 0, -6)) . '.php';
             return false;
         case 'User_openid':
-            require_once INSTALLDIR.'/plugins/OpenID/User_openid.php';
+            require_once dirname(__FILE__) . '/User_openid.php';
             return false;
         case 'User_openid_trustroot':
-            require_once INSTALLDIR.'/plugins/OpenID/User_openid_trustroot.php';
+            require_once dirname(__FILE__) . '/User_openid_trustroot.php';
+            return false;
+        case 'Auth_OpenID_TeamsExtension':
+        case 'Auth_OpenID_TeamsRequest':
+        case 'Auth_OpenID_TeamsResponse':
+            require_once dirname(__FILE__) . '/extlib/teams-extension.php';
             return false;
         default:
             return true;
@@ -442,7 +461,7 @@ class OpenIDPlugin extends Plugin
 
     function onRedirectToLogin($action, $user)
     {
-        if ($this->openidOnly || (!empty($user) && User_openid::hasOpenID($user->id))) {
+        if (common_config('site', 'openid_only') || (!empty($user) && User_openid::hasOpenID($user->id))) {
             common_redirect(common_local_url('openidlogin'), 303);
             return false;
         }
@@ -577,6 +596,32 @@ class OpenIDPlugin extends Plugin
         return true;
     }
 
+    /**
+     * Add an OpenID tab to the admin panel
+     *
+     * @param Widget $nav Admin panel nav
+     *
+     * @return boolean hook value
+     */
+
+    function onEndAdminPanelNav($nav)
+    {
+        if (AdminPanelAction::canAdmin('openid')) {
+
+            $action_name = $nav->action->trimmed('action');
+
+            $nav->out->menuItem(
+                common_local_url('openidadminpanel'),
+                _m('OpenID'),
+                _m('OpenID configuration'),
+                $action_name == 'openidadminpanel',
+                'nav_openid_admin_panel'
+            );
+        }
+
+        return true;
+    }
+
     /**
      * Add our version information to output
      *
diff --git a/plugins/OpenID/extlib/README b/plugins/OpenID/extlib/README
new file mode 100644 (file)
index 0000000..1fe80d7
--- /dev/null
@@ -0,0 +1,6 @@
+team-extension.php
+    Support for Launchpad's OpenID Teams extension
+    Maintainer: Canonical
+    Source: https://code.edge.launchpad.net/wordpress-teams-integration
+            r27 2010-04-27
+    License: AGPLv3
diff --git a/plugins/OpenID/extlib/teams-extension.php b/plugins/OpenID/extlib/teams-extension.php
new file mode 100644 (file)
index 0000000..451f2fb
--- /dev/null
@@ -0,0 +1,175 @@
+<?php
+/*
+ *  Wordpress Teams plugin
+ *  Copyright (C) 2009-2010 Canonical Ltd.
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU Affero General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU Affero General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Affero General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * Provides an example OpenID extension to query user team/group membership
+ *
+ * This code is based on code supplied with the openid library for simple
+ * registration data.
+ */
+
+/**
+ * Require the Message implementation.
+ */
+require_once 'Auth/OpenID/Message.php';
+require_once 'Auth/OpenID/Extension.php';
+
+/**
+ * The team/group extension base class
+ */
+class Auth_OpenID_TeamsExtension extends Auth_OpenID_Extension {
+  var $ns_uri = 'http://ns.launchpad.net/2007/openid-teams';
+  var $ns_alias = 'lp';
+  var $request_field = 'query_membership';
+  var $response_field = 'is_member';
+  
+  /**
+   * Get the string arguments that should be added to an OpenID
+   * message for this extension.
+   */
+  function getExtensionArgs() {
+    $args = array();
+
+    if ($this->_teams) {
+      $args[$this->request_field] = implode(',', $this->_teams);
+    }
+
+    return $args;
+  }
+
+  /**
+   * Add the arguments from this extension to the provided message.
+   *
+   * Returns the message with the extension arguments added.
+   */
+  function toMessage(&$message) {
+    if ($message->namespaces->addAlias($this->ns_uri, $this->ns_alias) === null) {
+      if ($message->namespaces->getAlias($this->ns_uri) != $this->ns_alias) {
+        return null;
+      }
+    }
+
+    $message->updateArgs($this->ns_uri, $this->getExtensionArgs());
+    return $message;
+  }
+  
+  /**
+   * Extract the team/group namespace URI from the given OpenID message.
+   * Handles OpenID 1 and 2.
+   *
+   * $message: The OpenID message from which to parse team/group data.
+   * This may be a request or response message.
+   *
+   * Returns the sreg namespace URI for the supplied message.
+   *
+   * @access private
+   */
+  function _getExtensionNS(&$message) {
+    $alias = null;
+    $found_ns_uri = null;
+
+    // See if there exists an alias for the namespace
+    $alias = $message->namespaces->getAlias($this->ns_uri);
+    
+    if ($alias !== null) {
+      $found_ns_uri = $this->ns_uri;
+    }
+
+    if ($alias === null) {
+      // There is no alias for this extension, so try to add one.
+      $found_ns_uri = Auth_OpenID_TYPE_1_0;
+      
+      if ($message->namespaces->addAlias($this->ns_uri, $this->ns_alias) === null) {
+        // An alias for the string 'lp' already exists, but
+        // it's defined for something other than team/group membership
+        return null;
+      }
+    }
+    
+    return $found_ns_uri;
+  }
+}
+
+/**
+ * The team/group extension request class
+ */
+class Auth_OpenID_TeamsRequest extends Auth_OpenID_TeamsExtension {
+  function __init($teams) {
+    if (!is_array($teams)) {
+      if (!empty($teams)) {
+        $teams = explode(',', $teams);
+      } else {
+        $teams = Array();
+      }
+    }
+    
+    $this->_teams = $teams;
+  }
+  
+  function Auth_OpenID_TeamsRequest($teams) {
+    $this->__init($teams);
+  }
+}
+
+/**
+ * The team/group extension response class
+ */
+class Auth_OpenID_TeamsResponse extends Auth_OpenID_TeamsExtension {
+  var $_teams = array();
+  
+  function __init(&$resp, $signed_only=true) {
+    $this->ns_uri = $this->_getExtensionNS($resp->message);
+    
+    if ($signed_only) {
+      $args = $resp->getSignedNS($this->ns_uri);
+    } else {
+      $args = $resp->message->getArgs($this->ns_uri);
+    }
+    
+    if ($args === null) {
+      return null;
+    }
+    
+    // An OpenID 2.0 response will handle the namespaces
+    if (in_array($this->response_field, array_keys($args)) && !empty($args[$this->response_field])) {
+      $this->_teams = explode(',', $args[$this->response_field]);
+    }
+    
+    // Piggybacking on a 1.x request, however, won't so the field name will
+    // be different
+    elseif (in_array($this->ns_alias.'.'.$this->response_field, array_keys($args)) && !empty($args[$this->ns_alias.'.'.$this->response_field])) {
+      $this->_teams = explode(',', $args[$this->ns_alias.'.'.$this->response_field]);
+    }
+  }
+  
+  function Auth_OpenID_TeamsResponse(&$resp, $signed_only=true) {
+    $this->__init($resp, $signed_only);
+  }
+  
+  /**
+   * Get the array of teams the user is a member of
+   *
+   * @return array
+   */
+  function getTeams() {
+    return $this->_teams;
+  }
+}
+
+?>
index 991e6584ee7ce07ac3402f93f1170fbaaaaf1adf..df1763a52cc3843aabbbe891d5a6ee28109a7ae7 100644 (file)
@@ -103,6 +103,12 @@ class FinishaddopenidAction extends Action
                 $sreg = $sreg_resp->contents();
             }
 
+            // Launchpad teams extension
+            if (!oid_check_teams($response)) {
+                $this->message(_m('OpenID authentication aborted: you are not allowed to login to this site.'));
+                return;
+            }
+
             $cur = common_current_user();
 
             $other = oid_get_user($canonical);
index 32b092a0bdefa896b38d18ef35c57eb552cd4c3c..57723ff97f33114c48786ca8a9adf3239770127f 100644 (file)
@@ -177,6 +177,12 @@ class FinishopenidloginAction extends Action
                 $sreg = $sreg_resp->contents();
             }
 
+            // Launchpad teams extension
+            if (!oid_check_teams($response)) {
+                $this->message(_m('OpenID authentication aborted: you are not allowed to login to this site.'));
+                return;
+            }
+
             $user = oid_get_user($canonical);
 
             if ($user) {
index 4ec336e1c3d95fb3b421db1e25dbbee7c770aae4..5ee9343d2818715c9e4f802510d8f98f695be52c 100644 (file)
@@ -164,6 +164,15 @@ function oid_authenticate($openid_url, $returnto, $immediate=false)
         $auth_request->addExtension($sreg_request);
     }
 
+    $requiredTeam = common_config('openid', 'required_team');
+    if ($requiredTeam) {
+        // LaunchPad OpenID extension
+        $team_request = new Auth_OpenID_TeamsRequest(array($requiredTeam));
+        if ($team_request) {
+            $auth_request->addExtension($team_request);
+        }
+    }
+
     $trust_root = common_root_url(true);
     $process_url = common_local_url($returnto);
 
@@ -286,6 +295,33 @@ function oid_assert_allowed($url)
     return;
 }
 
+/**
+ * Check the teams available in the given OpenID response
+ * Using Launchpad's OpenID teams extension
+ *
+ * @return boolean whether this user is acceptable
+ */
+function oid_check_teams($response)
+{
+    $requiredTeam = common_config('openid', 'required_team');
+    if ($requiredTeam) {
+        $team_resp = new Auth_OpenID_TeamsResponse($response);
+        if ($team_resp) {
+            $teams = $team_resp->getTeams();
+        } else {
+            $teams = array();
+        }
+
+        $match = in_array($requiredTeam, $teams);
+        $is = $match ? 'is' : 'is not';
+        common_log(LOG_DEBUG, "Remote user $is in required team $requiredTeam: [" . implode(', ', $teams) . "]");
+
+        return $match;
+    }
+
+    return true;
+}
+
 class AutosubmitAction extends Action
 {
     var $form_html = null;
diff --git a/plugins/OpenID/openidadminpanel.php b/plugins/OpenID/openidadminpanel.php
new file mode 100644 (file)
index 0000000..0633063
--- /dev/null
@@ -0,0 +1,270 @@
+<?php
+/**
+ * StatusNet, the distributed open-source microblogging tool
+ *
+ * OpenID bridge administration panel
+ *
+ * PHP version 5
+ *
+ * LICENCE: This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @category  Settings
+ * @package   StatusNet
+ * @author    Zach Copley <zach@status.net>
+ * @copyright 2010 StatusNet, Inc.
+ * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link      http://status.net/
+ */
+
+if (!defined('STATUSNET')) {
+    exit(1);
+}
+
+/**
+ * Administer global OpenID settings
+ *
+ * @category Admin
+ * @package  StatusNet
+ * @author   Zach Copley <zach@status.net>
+ * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
+ * @link     http://status.net/
+ */
+
+class OpenidadminpanelAction extends AdminPanelAction
+{
+    /**
+     * Returns the page title
+     *
+     * @return string page title
+     */
+
+    function title()
+    {
+        return _m('OpenID');
+    }
+
+    /**
+     * Instructions for using this form.
+     *
+     * @return string instructions
+     */
+
+    function getInstructions()
+    {
+        return _m('OpenID settings');
+    }
+
+    /**
+     * Show the OpenID admin panel form
+     *
+     * @return void
+     */
+
+    function showForm()
+    {
+        $form = new OpenIDAdminPanelForm($this);
+        $form->show();
+        return;
+    }
+
+    /**
+     * Save settings from the form
+     *
+     * @return void
+     */
+
+    function saveSettings()
+    {
+        static $settings = array(
+            'openid' => array('trusted_provider', 'required_team')
+        );
+
+        static $booleans = array(
+            'site' => array('openidonly')
+        );
+
+        $values = array();
+
+        foreach ($settings as $section => $parts) {
+            foreach ($parts as $setting) {
+                $values[$section][$setting]
+                    = $this->trimmed($setting);
+            }
+        }
+
+        foreach ($booleans as $section => $parts) {
+            foreach ($parts as $setting) {
+                $values[$section][$setting]
+                    = ($this->boolean($setting)) ? 1 : 0;
+            }
+        }
+
+        // This throws an exception on validation errors
+
+        $this->validate($values);
+
+        // assert(all values are valid);
+
+        $config = new Config();
+
+        $config->query('BEGIN');
+
+        foreach ($settings as $section => $parts) {
+            foreach ($parts as $setting) {
+                Config::save($section, $setting, $values[$section][$setting]);
+            }
+        }
+
+        foreach ($booleans as $section => $parts) {
+            foreach ($parts as $setting) {
+                Config::save($section, $setting, $values[$section][$setting]);
+            }
+        }
+
+        $config->query('COMMIT');
+
+        return;
+    }
+
+    function validate(&$values)
+    {
+        // Validate consumer key and secret (can't be too long)
+
+        if (mb_strlen($values['openid']['trusted_provider']) > 255) {
+            $this->clientError(
+                _m("Invalid provider URL. Max length is 255 characters.")
+            );
+        }
+
+        if (mb_strlen($values['openid']['required_team']) > 255) {
+            $this->clientError(
+                _m("Invalid team name. Max length is 255 characters.")
+            );
+        }
+    }
+}
+
+class OpenIDAdminPanelForm extends AdminForm
+{
+    /**
+     * ID of the form
+     *
+     * @return int ID of the form
+     */
+
+    function id()
+    {
+        return 'openidadminpanel';
+    }
+
+    /**
+     * class of the form
+     *
+     * @return string class of the form
+     */
+
+    function formClass()
+    {
+        return 'form_settings';
+    }
+
+    /**
+     * Action of the form
+     *
+     * @return string URL of the action
+     */
+
+    function action()
+    {
+        return common_local_url('openidadminpanel');
+    }
+
+    /**
+     * Data elements of the form
+     *
+     * @return void
+     *
+     * @todo Some of the options could prevent users from logging in again.
+     *       Make sure that the acting administrator has a valid OpenID matching,
+     *       or more carefully warn folks.
+     */
+
+    function formData()
+    {
+        $this->out->elementStart(
+            'fieldset',
+            array('id' => 'settings_openid')
+        );
+        $this->out->element('legend', null, _m('Trusted provider'));
+        $this->out->element('p', 'form_guide',
+            _m('By default, users are allowed to authenticate with any OpenID provider. ' .
+               'If you are using your own OpenID service for shared sign-in, ' .
+               'you can restrict access to only your own users here.'));
+        $this->out->elementStart('ul', 'form_data');
+
+        $this->li();
+        $this->input(
+            'trusted_provider',
+            _m('Provider URL'),
+            _m('All OpenID logins will be sent to this URL; other providers may not be used.'),
+            'openid'
+        );
+        $this->unli();
+
+        $this->li();
+        $this->input(
+            'required_team',
+             _m('Required team'),
+            _m('Only allow logins from users in the given team (Launchpad extension).'),
+            'openid'
+        );
+        $this->unli();
+
+        $this->out->elementEnd('ul');
+        $this->out->elementEnd('fieldset');
+
+        $this->out->elementStart(
+            'fieldset',
+            array('id' => 'settings_openid-options')
+        );
+        $this->out->element('legend', null, _m('Options'));
+
+        $this->out->elementStart('ul', 'form_data');
+
+        $this->li();
+
+        $this->out->checkbox(
+            'openidonly', _m('Enable OpenID-only mode'),
+            (bool) $this->value('openidonly', 'site'),
+            _m('Require all users to login via OpenID. WARNING: disables password authentication for all users!'),
+            'true'
+        );
+        $this->unli();
+
+        $this->out->elementEnd('ul');
+
+        $this->out->elementEnd('fieldset');
+    }
+
+    /**
+     * Action elements
+     *
+     * @return void
+     */
+
+    function formActions()
+    {
+        $this->out->submit('submit', _('Save'), 'submit', null, _m('Save OpenID settings'));
+    }
+}
index 2a743672cf68d2bfb59e4bcfa61c0239cccd489c..8c559c934637bc4704da96180c330a53df27247a 100644 (file)
@@ -29,7 +29,12 @@ class OpenidloginAction extends Action
         if (common_is_real_login()) {
             $this->clientError(_m('Already logged in.'));
         } else if ($_SERVER['REQUEST_METHOD'] == 'POST') {
-            $openid_url = $this->trimmed('openid_url');
+            $provider = common_config('openid', 'trusted_provider');
+            if ($provider) {
+                $openid_url = $provider;
+            } else {
+                $openid_url = $this->trimmed('openid_url');
+            }
 
             oid_assert_allowed($openid_url);
 
@@ -116,9 +121,18 @@ class OpenidloginAction extends Action
 
         $this->elementStart('ul', 'form_data');
         $this->elementStart('li');
-        $this->input('openid_url', _m('OpenID URL'),
-                     $this->openid_url,
-                     _m('Your OpenID URL'));
+        $provider = common_config('openid', 'trusted_provider');
+        if ($provider) {
+            $this->element('label', array(), _m('OpenID provider'));
+            $this->element('span', array(), $provider);
+            $this->element('p', 'form_guide',
+                           _m('You will be sent to the provider\'s site for authentication.'));
+            $this->hidden('openid_url', $provider);
+        } else {
+            $this->input('openid_url', _m('OpenID URL'),
+                         $this->openid_url,
+                         _m('Your OpenID URL'));
+        }
         $this->elementEnd('li');
         $this->elementStart('li', array('id' => 'settings_rememberme'));
         $this->checkbox('rememberme', _m('Remember me'), false,
index 16142cf48c36267a9e14a26ef7bbd35a01b1704b..505e7d0ee36574660804ad9d894a968ed9155333 100644 (file)
@@ -90,34 +90,36 @@ class OpenidsettingsAction extends AccountSettingsAction
     {
         $user = common_current_user();
 
-        $this->elementStart('form', array('method' => 'post',
-                                          'id' => 'form_settings_openid_add',
-                                          'class' => 'form_settings',
-                                          'action' =>
-                                          common_local_url('openidsettings')));
-        $this->elementStart('fieldset', array('id' => 'settings_openid_add'));
-        $this->element('legend', null, _m('Add OpenID'));
-        $this->hidden('token', common_session_token());
-        $this->element('p', 'form_guide',
-                       _m('If you want to add an OpenID to your account, ' .
-                         'enter it in the box below and click "Add".'));
-        $this->elementStart('ul', 'form_data');
-        $this->elementStart('li');
-        $this->element('label', array('for' => 'openid_url'),
-                       _m('OpenID URL'));
-        $this->element('input', array('name' => 'openid_url',
-                                      'type' => 'text',
-                                      'id' => 'openid_url'));
-        $this->elementEnd('li');
-        $this->elementEnd('ul');
-        $this->element('input', array('type' => 'submit',
-                                      'id' => 'settings_openid_add_action-submit',
-                                      'name' => 'add',
-                                      'class' => 'submit',
-                                      'value' => _m('Add')));
-        $this->elementEnd('fieldset');
-        $this->elementEnd('form');
-
+        if (!common_config('openid', 'trusted_provider')) {
+            $this->elementStart('form', array('method' => 'post',
+                                              'id' => 'form_settings_openid_add',
+                                              'class' => 'form_settings',
+                                              'action' =>
+                                              common_local_url('openidsettings')));
+            $this->elementStart('fieldset', array('id' => 'settings_openid_add'));
+    
+            $this->element('legend', null, _m('Add OpenID'));
+            $this->hidden('token', common_session_token());
+            $this->element('p', 'form_guide',
+                           _m('If you want to add an OpenID to your account, ' .
+                             'enter it in the box below and click "Add".'));
+            $this->elementStart('ul', 'form_data');
+            $this->elementStart('li');
+            $this->element('label', array('for' => 'openid_url'),
+                           _m('OpenID URL'));
+            $this->element('input', array('name' => 'openid_url',
+                                          'type' => 'text',
+                                          'id' => 'openid_url'));
+            $this->elementEnd('li');
+            $this->elementEnd('ul');
+            $this->element('input', array('type' => 'submit',
+                                          'id' => 'settings_openid_add_action-submit',
+                                          'name' => 'add',
+                                          'class' => 'submit',
+                                          'value' => _m('Add')));
+            $this->elementEnd('fieldset');
+            $this->elementEnd('form');
+        }
         $oid = new User_openid();
 
         $oid->user_id = $user->id;
@@ -234,10 +236,14 @@ class OpenidsettingsAction extends AccountSettingsAction
         }
 
         if ($this->arg('add')) {
-            $result = oid_authenticate($this->trimmed('openid_url'),
-                                       'finishaddopenid');
-            if (is_string($result)) { // error message
-                $this->showForm($result);
+            if (common_config('openid', 'trusted_provider')) {
+                $this->showForm(_m("Can't add new providers."));
+            } else {
+                $result = oid_authenticate($this->trimmed('openid_url'),
+                                           'finishaddopenid');
+                if (is_string($result)) { // error message
+                    $this->showForm($result);
+                }
             }
         } else if ($this->arg('remove')) {
             $this->removeOpenid();