跳转到主要内容

Django 1.6中的PySAML2集成

项目描述

djangosaml2-dj16

djangosaml2是Django 1.6应用程序,它将PySAML2库集成到您的项目中。这意味着您可以使用基于PySAML的服务提供商来保护您的Django项目。这样,它将与您的身份提供者进行SAML2通信,允许您使用此认证机制。本文档将引导您完成几个简单步骤以实现此目标。

安装

PySAML2使用xmlsec1二进制文件签名SAML断言,因此您需要通过操作系统包或通过编译源代码来安装它。最终的执行文件安装在哪里无关紧要,因为您需要在配置阶段设置其完整路径。

现在,您可以使用easy_install或pip安装djangosaml2包。这将自动安装PySAML2及其依赖项。

配置

为了让djangosaml2在您的Django项目中工作,您需要设置三件事情。

  1. settings.py,如您所知,这是Django的主要配置文件。

  2. urls.py是包含djangosaml2 URL的文件。

  3. pysaml2特定的文件,例如属性映射目录和证书。

settings.py文件中的更改

首先,您需要将djangosaml2添加到已安装的应用列表中。

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.admin',
    'djangosaml2',  # new application
)

实际上,这并不是必需的,因为djangosaml2不包括任何数据模型。我们包含它的唯一原因是可以从我们的项目中运行djangosaml2测试套件,这是您应该始终做的事情,以确保它与您的Django版本和环境兼容。

然后,您必须将djangosaml2.backends.Saml2Backend身份验证后端添加到身份验证后端列表中。默认情况下,仅配置了Django中包含的ModelBackend。一个典型的配置如下

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend',
    'djangosaml2.backends.Saml2Backend',
)

最后,我们必须告诉Django我们想要使用的新登录URL。

LOGIN_URL = '/saml2/login/'
SESSION_EXPIRE_AT_BROWSER_CLOSE = True

在这里,我们告诉Django,如果用户之前未通过认证,则需要认证的用户视图应将用户浏览器重定向到该URL。我们还告诉,当用户关闭浏览器时,会话应终止。这在SAML2联邦中非常有用,因为注销协议并不总是可用。

如果您想在项目中允许几种身份验证机制,则应将LOGIN_URL选项设置为另一个视图,并在该视图中放置一个链接到/saml2/login/视图。

urls.py文件中的更改

接下来,您需要将djangosaml2.urls模块包含到您的主urls.py模块中。

urlpatterns = patterns(
    '',
    #  lots of url definitions here

    (r'^saml2/', include('djangosaml2.urls')),

    #  more url definitions
)

如您所见,我们正在将djangosaml2.urls包含在saml2前缀下。您可以使用自己的前缀,但应与settings.py文件中LOGIN_URL参数中放置的内容保持一致。

PySAML2特定文件和配置

一旦完成Django项目的配置,就必须开始配置PySAML。如果您仅使用该库,则必须将配置选项放入文件中,并使用该文件的路径初始化PySAML2。

在djangosaml2中,只需将相同的信息放入Django settings.py文件下的SAML_CONFIG选项中。

我们将看到保护Django项目的典型配置。

from os import path
import saml2
BASEDIR = path.dirname(path.abspath(__file__))
SAML_CONFIG = {
  # full path to the xmlsec1 binary programm
  'xmlsec_binary': '/usr/bin/xmlsec1',

  # your entity id, usually your subdomain plus the url to the metadata view
  'entityid': 'http://localhost:8000/saml2/metadata/',

  # directory with attribute mapping
  'attribute_map_dir': path.join(BASEDIR, 'attribute-maps'),

  # this block states what services we provide
  'service': {
      # we are just a lonely SP
      'sp' : {
          'name': 'Federated Django sample SP',
          'endpoints': {
              # url and binding to the assetion consumer service view
              # do not change the binding or service name
              'assertion_consumer_service': [
                  ('http://localhost:8000/saml2/acs/',
                   saml2.BINDING_HTTP_POST),
                  ],
              # url and binding to the single logout service view
              # do not change the binding or service name
              'single_logout_service': [
                  ('http://localhost:8000/saml2/ls/',
                   saml2.BINDING_HTTP_REDIRECT),
                  ],
              },

           # attributes that this project need to identify a user
          'required_attributes': ['uid'],

           # attributes that may be useful to have but not required
          'optional_attributes': ['eduPersonAffiliation'],

          # in this section the list of IdPs we talk to are defined
          'idp': {
              # we do not need a WAYF service since there is
              # only an IdP defined here. This IdP should be
              # present in our metadata

              # the keys of this dictionary are entity ids
              'https://localhost/simplesaml/saml2/idp/metadata.php': {
                  'single_sign_on_service': {
                      saml2.BINDING_HTTP_REDIRECT: 'https://localhost/simplesaml/saml2/idp/SSOService.php',
                      },
                  'single_logout_service': {
                      saml2.BINDING_HTTP_REDIRECT: 'https://localhost/simplesaml/saml2/idp/SingleLogoutService.php',
                      },
                  },
              },
          },
      },

  # where the remote metadata is stored
  'metadata': {
      'local': [path.join(BASEDIR, 'remote_metadata.xml')],
      },

  # set to 1 to output debugging information
  'debug': 1,

  # certificate
  'key_file': path.join(BASEDIR, 'mycert.key'),  # private part
  'cert_file': path.join(BASEDIR, 'mycert.pem'),  # public part

  # own metadata settings
  'contact_person': [
      {'given_name': 'Lorenzo',
       'sur_name': 'Gil',
       'company': 'Yaco Sistemas',
       'email_address': 'lgs@yaco.es',
       'contact_type': 'technical'},
      {'given_name': 'Angel',
       'sur_name': 'Fernandez',
       'company': 'Yaco Sistemas',
       'email_address': 'angel@yaco.es',
       'contact_type': 'administrative'},
      ],
  # you can set multilanguage information here
  'organization': {
      'name': [('Yaco Sistemas', 'es'), ('Yaco Systems', 'en')],
      'display_name': [('Yaco', 'es'), ('Yaco', 'en')],
      'url': [('http://www.yaco.es', 'es'), ('http://www.yaco.com', 'en')],
      },
  'valid_for': 24,  # how long is our metadata valid
  }

根据此配置,您必须创建几个外部文件和目录。

在安装部分中提到了xmlsec1二进制文件。在此配置部分,您只需放置xmlsec1的完整路径,以便PySAML2可以在需要时调用它。

《attribute_map_dir》指向一个包含属性映射的目录,这些映射用于将用户属性名称从多个标准翻译过来。通常情况下,只需复制源分发版中《tests/attributemaps》目录下的默认 PySAML2 属性映射即可,这是安全的。

metadata 选项是一个字典,您可以在其中定义远程实体的一些元数据类型。通常最简单的一种类型是《local》,您只需放置一个包含远程实体元数据内容的本地 XML 文件的名称。这个 XML 文件应该是 SAML2 元数据格式。

key_filecert_file 选项引用标准 x509 证书的两个部分。您需要它来签名元数据,并加密和解密 SAML2 断言。

自定义和动态配置加载

默认情况下,djangosaml2 从 SAML_CONFIG 设置读取 pysaml2 配置选项,但有时您可能希望从其他地方读取这些信息,例如文件或数据库。有时,您甚至希望这些配置根据请求而不同。

从 djangosaml2 0.5.0 版本开始,您可以定义自己的配置加载器,它是一个可调用的对象,接受一个请求参数并返回一个 saml2.config.SPConfig 对象。为了实现这一点,您需要设置以下设置

SAML_CONFIG_LOADER = 'python.path.to.your.callable'

用户属性

在 SAML 2.0 认证过程中,身份提供者(IdP)将在认证成功后向服务提供者(SP)发送一个安全断言。这个断言包含有关已认证用户的属性。确切哪些属性被发送到每个 SP 取决于 IdP 的配置。

当在 Django 侧接收到这样的断言时,它被用来查找 Django 用户并为它创建一个会话。默认情况下,djangosaml2 将对 User 模型进行查询,使用的是‘username’属性,但您可以将它更改为 User 模型的任何其他属性。例如,您可以使用‘email’属性进行查找。为此,您应该设置以下设置

SAML_DJANGO_USER_MAIN_ATTRIBUTE = 'email'

请,在设置此选项时使用唯一属性。否则,由于 djangosaml2 无法确定它应该选择哪个 Django 用户,认证过程将失败。

您可以将 djangosaml2 配置为在它不在 Django 数据库中时创建此类用户,或者您可能不想允许那些不在您数据库中的用户。为此,在 settings.py 文件中还有另一个选项可以设置

SAML_CREATE_UNKNOWN_USER = True

此设置默认为 True。

您可能还需要配置 SAML2 用户属性到 Django 用户属性的映射。默认情况下,只映射 User.username 属性,但您可以添加更多属性或更改它。为此,您需要在 settings.py 中更改 SAML_ATTRIBUTE_MAPPING 选项

SAML_ATTRIBUTE_MAPPING = {
    'uid': ('username', ),
    'mail': ('email', ),
    'cn': ('first_name', ),
    'sn': ('last_name', ),
}

其中,该字典的键是 SAML 用户属性,值是 Django User 属性。

如果您正在使用 Django 用户配置文件对象来存储有关用户的额外属性,您可以将这些属性添加到 SAML_ATTRIBUTE_MAPPING 字典中。对于每个(键,值)对,djangosaml2 将尝试在模型中存储属性,如果该模型中有匹配的字段。否则,它将尝试使用您的自定义配置文件模型执行相同操作。

有关 Django 配置文件模型的更多信息,请参阅

https://docs.django.ac.cn/en/dev/topics/auth/#storing-additional-information-about-users

有时您需要使用特殊逻辑来根据 SAML2 属性和上述映射更新用户对象,而上述映射可能不够。在这些情况下,djangosaml2 提供了一个 Django 信号,您可以监听它。为此,您可以将以下代码添加到您的应用程序中

from djangosaml2.signals import pre_user_save

def custom_update_user(sender=user, attributes=attributes, user_modified=user_modified)
   ...
   return True  # I modified the user object

您的处理程序将接收到用户对象、SAML属性列表以及一个标志,告诉您用户是否已被修改并在您的处理程序执行后需要保存。如果您的处理程序修改了用户对象,它应该返回True。否则,它应该返回False。这样,djangosaml2将知道是否需要保存用户对象,因此您不需要这样做,并且不再发出对save方法的调用。

IdP设置

恭喜您,您已经完成了联盟的SP端配置。现在,您需要将这个新SP的实体ID和元数据发送给IdP管理员,以便他们将其添加到他们信任的服务列表中。

您可以通过启动Django开发服务器并访问http://localhost:8000/saml2/metadata URL来获取这些信息。如果您已将djangosaml2 URL包含在不同的URL前缀下,您需要更正此URL。

SimpleSAMLphp问题

从SimpleSAMLphp 1.8.2版本开始,如果在SP配置中指定了属性,将存在一个问题。当SimpleSAMLphp元数据解析器将XML转换为自定义的PHP格式时,它会放置以下选项

'attributes.NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri'

但需要替换为这个

'AttributeNameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri'

否则,从IdP发送到SP的断言将具有错误的属性名称格式,pysaml2会感到困惑。

此外,如果您在SimpleSAMLphp配置中有一个AttributeLimit过滤器,您需要在它之前启用另一个属性过滤器,以确保AttributeLimit不会从身份验证源删除属性。您需要添加的过滤器是一个类似于这样的AttributeMap过滤器

10 => array(
           'class' => 'core:AttributeMap', 'name2oid'
      ),

测试

检查一切是否按预期工作的一种方法是通过启用以下URL

urlpatterns = patterns(
    '',
    #  lots of url definitions here

    (r'^saml2/', include('djangosaml2.urls')),
    (r'^test/', 'djangosaml2.views.echo_attributes'),

    #  more url definitions
)

现在,如果您访问/test/ URL,您将看到您的SAML属性,还有一个全局注销的链接。

您还可以使用以下命令运行单元测试

python tests/run_tests.py

如果您已安装tox,您只需在根目录中调用tox,它将在多个Python版本中运行测试。

常见问题解答

为什么不能将SAML实现为Django身份验证后端?

好吧,SAML身份验证不像登录表单上可以放置的一组凭据那样简单。实际上,用户密码根本不会提供给服务提供商。这是设计决定的。您必须将身份验证任务委托给IdP,然后从它那里获得异步响应。

鉴于上述情况,djangosaml2确实使用Django身份验证后端将关于用户的SAML断言转换为Django用户对象。

为什么不将所有内容放入Django中间件类中,让我们的生活更轻松?

是的,这是一个我确实评估过的选项,但最终当前的设计获胜。在我看来,将此逻辑放入中间件的优势是使其更容易配置,但有几个缺点:首先,中间件需要检查对于每个请求,请求路径是否为SAML端点之一。其次,它将过于神奇,如果在出现问题时,调试将更加困难。

为什么不将此包命名为django-saml,像许多其他Django应用程序一样?

按照该模式,我应该用import saml导入应用程序,但不幸的是,该模块名称已在pysaml2中使用。

更改

0.10.0 (2013-05-05)

  • 在重定向到循环之前,检查RelayState是否为空。感谢Sam Bull报告此问题。

  • 在全局注销过程中,当会话丢失时,向用户报告错误消息并执行本地注销。

0.9.2 (2013-04-19)

  • 升级到pysaml2-0.4.3。

0.9.1 (2013-01-29)

  • 向身份验证后端添加一个方法,以便可以根据SAML属性自定义授权。

0.9.0 (2012-10-30)

  • 在身份验证后端的update_user方法中修改用户之前,添加一个信号。

0.8.1 (2012-10-29)

  • 在将SAML属性设置到Django对象之前,如果它们太长,则对其进行修剪。这修复了与MySQL相关的崩溃。

0.8.0 (2012-10-25)

  • 允许使用除“username”之外的不同属性来查找现有用户。

0.7.0 (2012-10-19)

  • 添加一个设置来决定当用户尝试登录两次时,是否将用户重定向到下一个视图或显示授权错误。

0.6.1 (2012-09-03)

  • 从我们的依赖中移除Django。

  • 恢复对Django 1.3的支持。

0.6.0 (2012-08-29)

  • 添加tox支持,配置为使用Python 2.6和2.7运行测试。

  • 修复一些依赖项和sdist生成。作者:Lorenzo Gil

  • 允许在设置中定义注销重定向URL。作者:Lorenzo Gil

  • 添加一些日志调用以改进调试。作者:Lorenzo Gil

  • 添加对自定义配置加载函数的支持。作者:Sam Bull

  • 使测试在djangosaml2包含在Django项目中时更健壮且更容易运行。作者:Sam Bull

  • 在保存之前确保配置文件不是None。问题报告者:Leif Johansson

0.5.0 (2012-05-22)

  • 允许定义自定义配置加载器。它们可以根据请求动态。

  • 不要自动添加认证后端。这样我们允许其他人添加他们自己的后端。

  • 支持除映射到用户模型之外的其他属性。这些属性存储在UserProfile模型中。

0.4.2 (2012-03-23)

  • 修复idplist模板标签中关于使用旧pysaml2函数的崩溃。

  • 为之前的崩溃添加了一个测试。

0.4.1 (2012-03-19)

  • 将pysaml2依赖项升级到版本0.4.1。

0.4.0 (2012-03-18)

  • 将pysaml2依赖项升级到版本0.4.0(由于此更新,更新我们的测试)。

  • 添加日志调用以简化调试。

  • 在pysaml2中使用Django配置的日志记录器。

0.3.3 (2012-02-14)

  • 冻结pysaml2的版本,因为我们(目前!)与版本0.4.0不兼容。

0.3.2 (2011-12-13)

  • 避免读取映射到Django用户名的SAML属性时崩溃。

0.3.1 (2011-12-01)

  • 在idplist模板标签的render方法中加载配置,使其更灵活且可重入。

0.3.0 (2011-11-30)

  • 获取可用IDP列表的模板标签。

  • 允许将相同的SAML属性映射到多个Django字段。

0.2.4 (2011-11-29)

  • 修复restructured text错误,这些错误使pypi页面看起来很糟糕。

0.2.3 (2011-06-14)

  • 在首次创建用户时设置不可用的密码。

0.2.2 (2011-06-07)

  • 当用户已登录且设置.LOGIN_REDIRECT_URL(不好)指向/saml2/login时,防止进入/saml2/login/端点时的无限循环。

0.2.1 (2011-05-09)

  • 如果没有提供next参数给登录视图,则使用设置.LOGIN_REDIRECT_URL作为默认值。

0.2.0 (2011-04-26)

  • 如果安装了elementtree库,则与Python 2.4兼容。

  • 允许通过使用Django信号在认证阶段之后进行后处理。

0.1.1 (2011-04-18)

  • 简单的回显SAML属性的视图。

  • 改进文档。

  • 更改创建新用户时的默认行为。现在,它们的属性在第一次填充。

  • 允许在注销后设置下一页。

0.1.0 (2011-03-16)

  • 从pysaml包中解放。

项目详情


下载文件

下载适用于您的平台的文件。如果您不确定要选择哪个,请了解更多关于安装包的信息。

源分发

djangosaml2-dj16-0.10.0.tar.gz (62.4 KB 查看哈希值

上传时间:

由以下组织支持