mirror of
https://github.com/vmware/vsphere-automation-sdk-python.git
synced 2024-11-30 04:10:00 -05:00
532 lines
50 KiB
HTML
532 lines
50 KiB
HTML
|
|
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
|
|
|
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
|
|
<title>vmware.vapi.security.sso — vSphere Automation SDK for Python 6.5.0 documentation</title>
|
|
|
|
<link rel="stylesheet" href="../../../../_static/vapitheme.css" type="text/css" />
|
|
<link rel="stylesheet" href="../../../../_static/pygments.css" type="text/css" />
|
|
|
|
<script type="text/javascript">
|
|
var DOCUMENTATION_OPTIONS = {
|
|
URL_ROOT: '../../../../',
|
|
VERSION: '6.5.0',
|
|
COLLAPSE_INDEX: false,
|
|
FILE_SUFFIX: '.html',
|
|
HAS_SOURCE: true
|
|
};
|
|
</script>
|
|
<script type="text/javascript" src="../../../../_static/jquery.js"></script>
|
|
<script type="text/javascript" src="../../../../_static/underscore.js"></script>
|
|
<script type="text/javascript" src="../../../../_static/doctools.js"></script>
|
|
<link rel="top" title="vSphere Automation SDK for Python 6.5.0 documentation" href="../../../../index.html" />
|
|
<link rel="up" title="Module code" href="../../../index.html" />
|
|
</head>
|
|
<body>
|
|
<div class="related">
|
|
<h3>Navigation</h3>
|
|
<ul>
|
|
<li class="right" style="margin-right: 10px">
|
|
<a href="../../../../genindex.html" title="General Index"
|
|
accesskey="I">index</a></li>
|
|
<li class="right" >
|
|
<a href="../../../../py-modindex.html" title="Python Module Index"
|
|
>modules</a> |</li>
|
|
<li><a href="../../../../index.html">vSphere Automation SDK for Python 6.5.0 documentation</a> »</li>
|
|
<li><a href="../../../index.html" accesskey="U">Module code</a> »</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div class="document">
|
|
<div class="documentwrapper">
|
|
<div class="bodywrapper">
|
|
<div class="body">
|
|
|
|
<h1>Source code for vmware.vapi.security.sso</h1><div class="highlight"><pre>
|
|
<span class="sd">"""</span>
|
|
<span class="sd">SSO Security Helper</span>
|
|
<span class="sd">"""</span>
|
|
|
|
<span class="n">__author__</span> <span class="o">=</span> <span class="s">'VMware, Inc.'</span>
|
|
<span class="n">__copyright__</span> <span class="o">=</span> <span class="s">'Copyright (c) 2015 VMware, Inc. All rights reserved.'</span>
|
|
|
|
<span class="kn">from</span> <span class="nn">base64</span> <span class="kn">import</span> <span class="n">b64encode</span><span class="p">,</span> <span class="n">b64decode</span>
|
|
<span class="kn">import</span> <span class="nn">datetime</span>
|
|
<span class="kn">import</span> <span class="nn">decimal</span>
|
|
<span class="kn">import</span> <span class="nn">logging</span>
|
|
<span class="kn">from</span> <span class="nn">lxml</span> <span class="kn">import</span> <span class="n">etree</span>
|
|
<span class="kn">from</span> <span class="nn">OpenSSL</span> <span class="kn">import</span> <span class="n">crypto</span>
|
|
<span class="kn">import</span> <span class="nn">re</span>
|
|
<span class="k">try</span><span class="p">:</span>
|
|
<span class="kn">import</span> <span class="nn">simplejson</span> <span class="kn">as</span> <span class="nn">json</span>
|
|
<span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
|
|
<span class="kn">import</span> <span class="nn">json</span>
|
|
|
|
<span class="kn">from</span> <span class="nn">vmware.vapi.bindings.datetime_helper</span> <span class="kn">import</span> <span class="n">DateTimeConverter</span>
|
|
<span class="kn">from</span> <span class="nn">vmware.vapi.core</span> <span class="kn">import</span> <span class="n">SecurityContext</span>
|
|
<span class="kn">from</span> <span class="nn">vmware.vapi.lib.jsonlib</span> <span class="kn">import</span> <span class="p">(</span>
|
|
<span class="n">DecimalEncoder</span><span class="p">,</span> <span class="n">canonicalize_double</span><span class="p">)</span>
|
|
<span class="kn">from</span> <span class="nn">vmware.vapi.lib.constants</span> <span class="kn">import</span> <span class="p">(</span>
|
|
<span class="n">PARAMS</span><span class="p">,</span> <span class="n">SCHEME_ID</span><span class="p">,</span> <span class="n">EXECUTION_CONTEXT</span><span class="p">,</span> <span class="n">SECURITY_CONTEXT</span><span class="p">)</span>
|
|
<span class="kn">from</span> <span class="nn">vmware.vapi.protocol.common.lib</span> <span class="kn">import</span> <span class="n">RequestProcessor</span>
|
|
<span class="kn">from</span> <span class="nn">vmware.vapi.settings</span> <span class="kn">import</span> <span class="n">config</span>
|
|
|
|
<span class="n">key_regex</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="s">r'-----BEGIN [A-Z ]*PRIVATE KEY-----\n'</span><span class="p">)</span>
|
|
<span class="n">SAML_SCHEME_ID</span> <span class="o">=</span> <span class="s">'com.vmware.vapi.std.security.saml_hok_token'</span>
|
|
<span class="n">SAML_BEARER_SCHEME_ID</span> <span class="o">=</span> <span class="s">'com.vmware.vapi.std.security.saml_bearer_token'</span>
|
|
<span class="n">PRIVATE_KEY</span> <span class="o">=</span> <span class="s">'privateKey'</span>
|
|
<span class="n">SAML_TOKEN</span> <span class="o">=</span> <span class="s">'samlToken'</span>
|
|
<span class="n">SIGNATURE_ALGORITHM</span> <span class="o">=</span> <span class="s">'signatureAlgorithm'</span>
|
|
<span class="n">DEFAULT_ALGORITHM_TYPE</span> <span class="o">=</span> <span class="s">'RS256'</span>
|
|
<span class="n">TIMESTAMP</span> <span class="o">=</span> <span class="s">'timestamp'</span>
|
|
<span class="n">EXPIRES</span> <span class="o">=</span> <span class="s">'expires'</span>
|
|
<span class="n">CREATED</span> <span class="o">=</span> <span class="s">'created'</span>
|
|
<span class="n">REQUEST_VALIDITY</span> <span class="o">=</span> <span class="mi">20</span>
|
|
<span class="n">SIGNATURE</span> <span class="o">=</span> <span class="s">'signature'</span>
|
|
<span class="n">DIGEST</span> <span class="o">=</span> <span class="s">'value'</span>
|
|
<span class="n">AUTHENTICATED</span> <span class="o">=</span> <span class="s">'requestAuthenticated'</span>
|
|
<span class="n">STS_URL_PROP</span> <span class="o">=</span> <span class="s">'stsurl'</span>
|
|
<span class="n">CERTIFICATE_PROP</span> <span class="o">=</span> <span class="s">'certificate'</span>
|
|
<span class="n">PRIVATE_KEY_PROP</span> <span class="o">=</span> <span class="s">'privatekey'</span>
|
|
<span class="n">SECTION</span> <span class="o">=</span> <span class="n">__name__</span>
|
|
<span class="c"># Algorithm Header Parameter Values for JWS based on the following link</span>
|
|
<span class="c"># https://datatracker.ietf.org/doc/draft-ietf-jose-json-web-algorithms/?include_text=1</span>
|
|
<span class="n">algorithm_map</span> <span class="o">=</span> <span class="p">{</span>
|
|
<span class="s">'RS256'</span><span class="p">:</span> <span class="s">'sha256'</span><span class="p">,</span>
|
|
<span class="s">'RS384'</span><span class="p">:</span> <span class="s">'sha384'</span><span class="p">,</span>
|
|
<span class="s">'RS512'</span><span class="p">:</span> <span class="s">'sha512'</span><span class="p">,</span>
|
|
<span class="p">}</span>
|
|
|
|
<span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span>
|
|
|
|
|
|
<div class="viewcode-block" id="setup_saml_token_processors"><a class="viewcode-back" href="../../../../vmware.vapi.security.html#vmware.vapi.security.sso.setup_saml_token_processors">[docs]</a><span class="k">def</span> <span class="nf">setup_saml_token_processors</span><span class="p">():</span>
|
|
<span class="sd">"""</span>
|
|
<span class="sd"> If SAML token based authentication scheme is used, this operation</span>
|
|
<span class="sd"> should be invoked by the client to setup the request processors</span>
|
|
<span class="sd"> that does the request signing using the token.</span>
|
|
<span class="sd"> """</span>
|
|
<span class="k">if</span> <span class="ow">not</span> <span class="n">config</span><span class="o">.</span><span class="n">cfg</span><span class="o">.</span><span class="n">has_section</span><span class="p">(</span>
|
|
<span class="s">'vmware.vapi.protocol.client.msg.json_connector'</span><span class="p">):</span>
|
|
<span class="n">config</span><span class="o">.</span><span class="n">cfg</span><span class="o">.</span><span class="n">add_section</span><span class="p">(</span><span class="s">'vmware.vapi.protocol.client.msg.json_connector'</span><span class="p">)</span>
|
|
<span class="n">config</span><span class="o">.</span><span class="n">cfg</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s">'vmware.vapi.protocol.client.msg.json_connector'</span><span class="p">,</span>
|
|
<span class="s">'processors'</span><span class="p">,</span>
|
|
<span class="s">'vmware.vapi.security.sso.JSONSSOSigner'</span><span class="p">)</span>
|
|
|
|
</div>
|
|
<div class="viewcode-block" id="create_saml_bearer_security_context"><a class="viewcode-back" href="../../../../vmware.vapi.security.html#vmware.vapi.security.sso.create_saml_bearer_security_context">[docs]</a><span class="k">def</span> <span class="nf">create_saml_bearer_security_context</span><span class="p">(</span><span class="n">token</span><span class="p">):</span>
|
|
<span class="sd">"""</span>
|
|
<span class="sd"> Create a security context for SAML bearer token based</span>
|
|
<span class="sd"> authentication scheme</span>
|
|
|
|
<span class="sd"> :type token: :class:`str`</span>
|
|
<span class="sd"> :param token: SAML Token</span>
|
|
<span class="sd"> """</span>
|
|
<span class="k">return</span> <span class="n">SecurityContext</span><span class="p">({</span><span class="n">SCHEME_ID</span><span class="p">:</span> <span class="n">SAML_BEARER_SCHEME_ID</span><span class="p">,</span>
|
|
<span class="n">SAML_TOKEN</span><span class="p">:</span> <span class="n">token</span><span class="p">})</span>
|
|
|
|
</div>
|
|
<div class="viewcode-block" id="create_saml_security_context"><a class="viewcode-back" href="../../../../vmware.vapi.security.html#vmware.vapi.security.sso.create_saml_security_context">[docs]</a><span class="k">def</span> <span class="nf">create_saml_security_context</span><span class="p">(</span><span class="n">token</span><span class="p">,</span> <span class="n">private_key</span><span class="p">):</span>
|
|
<span class="sd">"""</span>
|
|
<span class="sd"> Create a security context for SAML token based</span>
|
|
<span class="sd"> authentication scheme</span>
|
|
|
|
<span class="sd"> :type token: :class:`str`</span>
|
|
<span class="sd"> :param token: SAML Token</span>
|
|
<span class="sd"> :type private_key: :class:`str`</span>
|
|
<span class="sd"> :param private_key: Absolute file path of the private key of the user</span>
|
|
<span class="sd"> :rtype: :class:`vmware.vapi.core.SecurityContext`</span>
|
|
<span class="sd"> :return: Newly created security context</span>
|
|
<span class="sd"> """</span>
|
|
<span class="n">private_key_data</span> <span class="o">=</span> <span class="bp">None</span>
|
|
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">private_key</span><span class="p">,</span> <span class="s">'r'</span><span class="p">)</span> <span class="k">as</span> <span class="n">fp</span><span class="p">:</span>
|
|
<span class="n">private_key_data</span> <span class="o">=</span> <span class="n">fp</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
|
|
<span class="k">return</span> <span class="n">SecurityContext</span><span class="p">({</span><span class="n">SCHEME_ID</span><span class="p">:</span> <span class="n">SAML_SCHEME_ID</span><span class="p">,</span>
|
|
<span class="n">PRIVATE_KEY</span><span class="p">:</span> <span class="n">private_key_data</span><span class="p">,</span>
|
|
<span class="n">SAML_TOKEN</span><span class="p">:</span> <span class="n">token</span><span class="p">,</span>
|
|
<span class="n">SIGNATURE_ALGORITHM</span><span class="p">:</span> <span class="n">DEFAULT_ALGORITHM_TYPE</span><span class="p">})</span>
|
|
|
|
</div>
|
|
<div class="viewcode-block" id="JSONCanonicalEncoder"><a class="viewcode-back" href="../../../../vmware.vapi.security.html#vmware.vapi.security.sso.JSONCanonicalEncoder">[docs]</a><span class="k">class</span> <span class="nc">JSONCanonicalEncoder</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">JSONEncoder</span><span class="p">):</span>
|
|
<span class="sd">"""</span>
|
|
<span class="sd"> Custom JSON Encoder class to canonicalize dictionary</span>
|
|
<span class="sd"> and list objects</span>
|
|
<span class="sd"> """</span>
|
|
<div class="viewcode-block" id="JSONCanonicalEncoder.encode"><a class="viewcode-back" href="../../../../vmware.vapi.security.html#vmware.vapi.security.sso.JSONCanonicalEncoder.encode">[docs]</a> <span class="k">def</span> <span class="nf">encode</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">o</span><span class="p">):</span>
|
|
<span class="sd">"""</span>
|
|
<span class="sd"> Encode a given python object</span>
|
|
|
|
<span class="sd"> :type o: :class:`object`</span>
|
|
<span class="sd"> :param o: Python object</span>
|
|
<span class="sd"> :rtype: :class:`str`</span>
|
|
<span class="sd"> :return: JSON string in canonicalized form</span>
|
|
<span class="sd"> """</span>
|
|
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">o</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
|
|
<span class="c"># Remove non-significant whitespace characters</span>
|
|
<span class="c"># Keys are sorted lexicographically using UCS code</span>
|
|
<span class="c"># point values</span>
|
|
<span class="n">sorted_keys</span> <span class="o">=</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">o</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
|
|
<span class="n">sorted_items</span> <span class="o">=</span> <span class="p">[</span><span class="s">'</span><span class="si">%s</span><span class="s">:</span><span class="si">%s</span><span class="s">'</span> <span class="o">%</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="n">key</span><span class="p">),</span>
|
|
<span class="bp">self</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="n">o</span><span class="p">[</span><span class="n">key</span><span class="p">]))</span>
|
|
<span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">sorted_keys</span><span class="p">]</span>
|
|
<span class="n">string</span> <span class="o">=</span> <span class="s">','</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">sorted_items</span><span class="p">)</span>
|
|
<span class="k">return</span> <span class="s">'{</span><span class="si">%s</span><span class="s">}'</span> <span class="o">%</span> <span class="n">string</span>
|
|
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">o</span><span class="p">,</span> <span class="nb">list</span><span class="p">):</span>
|
|
<span class="c"># Arrays must preserve the initial ordering</span>
|
|
<span class="c"># Remove non-significant whitespace characters</span>
|
|
<span class="n">string</span> <span class="o">=</span> <span class="s">','</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="bp">self</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="n">item</span><span class="p">)</span>
|
|
<span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">o</span><span class="p">])</span>
|
|
<span class="k">return</span> <span class="s">'[</span><span class="si">%s</span><span class="s">]'</span> <span class="o">%</span> <span class="n">string</span>
|
|
<span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">o</span><span class="p">,</span> <span class="n">decimal</span><span class="o">.</span><span class="n">Decimal</span><span class="p">):</span>
|
|
<span class="k">return</span> <span class="n">canonicalize_double</span><span class="p">(</span><span class="n">o</span><span class="p">)</span>
|
|
<span class="k">else</span><span class="p">:</span>
|
|
<span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">JSONEncoder</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">o</span><span class="p">)</span>
|
|
|
|
</div></div>
|
|
<div class="viewcode-block" id="JSONCanonicalizer"><a class="viewcode-back" href="../../../../vmware.vapi.security.html#vmware.vapi.security.sso.JSONCanonicalizer">[docs]</a><span class="k">class</span> <span class="nc">JSONCanonicalizer</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
|
|
<span class="sd">"""</span>
|
|
<span class="sd"> This class is responsible for transforming JSON messages into their</span>
|
|
<span class="sd"> canonical representation.</span>
|
|
|
|
<span class="sd"> The canonical form is defined by the following rules:</span>
|
|
<span class="sd"> 1. Non-significant(1) whitespace characters MUST NOT be used</span>
|
|
<span class="sd"> 2. Non-significant(1) line endings MUST NOT be used</span>
|
|
<span class="sd"> 3. Entries (set of name/value pairs) in JSON objects MUST be sorted</span>
|
|
<span class="sd"> lexicographically(2) by their names based on UCS codepoint values</span>
|
|
<span class="sd"> 4. Arrays MUST preserve their initial ordering</span>
|
|
|
|
<span class="sd"> Link to the IEFT proposal:</span>
|
|
<span class="sd"> https://datatracker.ietf.org/doc/draft-staykov-hu-json-canonical-form/</span>
|
|
<span class="sd"> """</span>
|
|
<span class="nd">@staticmethod</span>
|
|
<div class="viewcode-block" id="JSONCanonicalizer.canonicalize"><a class="viewcode-back" href="../../../../vmware.vapi.security.html#vmware.vapi.security.sso.JSONCanonicalizer.canonicalize">[docs]</a> <span class="k">def</span> <span class="nf">canonicalize</span><span class="p">(</span><span class="n">input_message</span><span class="p">):</span>
|
|
<span class="sd">"""</span>
|
|
<span class="sd"> Canonicalize the input message</span>
|
|
|
|
<span class="sd"> :type input_message: :class:`str`</span>
|
|
<span class="sd"> :param input_message: Input message</span>
|
|
<span class="sd"> :rtype: :class:`str`</span>
|
|
<span class="sd"> :return: Canonicalized message</span>
|
|
<span class="sd"> """</span>
|
|
<span class="n">py_obj</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">input_message</span><span class="p">,</span> <span class="n">parse_float</span><span class="o">=</span><span class="n">decimal</span><span class="o">.</span><span class="n">Decimal</span><span class="p">)</span>
|
|
<span class="k">return</span> <span class="n">JSONCanonicalEncoder</span><span class="p">()</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="n">py_obj</span><span class="p">)</span>
|
|
</div>
|
|
<span class="nd">@staticmethod</span>
|
|
<div class="viewcode-block" id="JSONCanonicalizer.canonicalize_py_obj"><a class="viewcode-back" href="../../../../vmware.vapi.security.html#vmware.vapi.security.sso.JSONCanonicalizer.canonicalize_py_obj">[docs]</a> <span class="k">def</span> <span class="nf">canonicalize_py_obj</span><span class="p">(</span><span class="n">py_obj</span><span class="p">):</span>
|
|
<span class="sd">"""</span>
|
|
<span class="sd"> Canonicalize the input python object</span>
|
|
|
|
<span class="sd"> :type input_message: :class:`object`</span>
|
|
<span class="sd"> :param input_message: Input python object</span>
|
|
<span class="sd"> :rtype: :class:`str`</span>
|
|
<span class="sd"> :return: Canonicalized message</span>
|
|
<span class="sd"> """</span>
|
|
<span class="k">return</span> <span class="n">JSONCanonicalEncoder</span><span class="p">()</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="n">py_obj</span><span class="p">)</span>
|
|
|
|
</div></div>
|
|
<div class="viewcode-block" id="JSONSSOSigner"><a class="viewcode-back" href="../../../../vmware.vapi.security.html#vmware.vapi.security.sso.JSONSSOSigner">[docs]</a><span class="k">class</span> <span class="nc">JSONSSOSigner</span><span class="p">(</span><span class="n">RequestProcessor</span><span class="p">):</span>
|
|
<span class="sd">"""</span>
|
|
<span class="sd"> This class is used for signing JSON request messages</span>
|
|
<span class="sd"> """</span>
|
|
<div class="viewcode-block" id="JSONSSOSigner.process"><a class="viewcode-back" href="../../../../vmware.vapi.security.html#vmware.vapi.security.sso.JSONSSOSigner.process">[docs]</a> <span class="k">def</span> <span class="nf">process</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">input_message</span><span class="p">):</span>
|
|
<span class="sd">"""</span>
|
|
<span class="sd"> Sign the input JSON request message.</span>
|
|
|
|
<span class="sd"> The message is signed using user's private key. The digest and saml</span>
|
|
<span class="sd"> token is then added to the security context block of the execution</span>
|
|
<span class="sd"> context. A timestamp is also added to guard against replay attacks</span>
|
|
|
|
<span class="sd"> Sample input security context:</span>
|
|
<span class="sd"> {</span>
|
|
<span class="sd"> 'schemeId': 'SAML_TOKEN',</span>
|
|
<span class="sd"> 'privateKey': <PRIVATE_KEY>,</span>
|
|
<span class="sd"> 'samlToken': <SAML_TOKEN>,</span>
|
|
<span class="sd"> 'signatureAlgorithm': <ALGORITHM>,</span>
|
|
<span class="sd"> }</span>
|
|
|
|
<span class="sd"> Security context block before signing:</span>
|
|
<span class="sd"> {</span>
|
|
<span class="sd"> 'schemeId': 'SAML_TOKEN',</span>
|
|
<span class="sd"> 'signatureAlgorithm': <ALGORITHM>,</span>
|
|
<span class="sd"> 'timestamp': {</span>
|
|
<span class="sd"> 'created': '2012-10-26T12:24:18.941Z',</span>
|
|
<span class="sd"> 'expires': '2012-10-26T12:44:18.941Z',</span>
|
|
<span class="sd"> }</span>
|
|
<span class="sd"> }</span>
|
|
|
|
<span class="sd"> Security context block after signing:</span>
|
|
<span class="sd"> {</span>
|
|
<span class="sd"> 'schemeId': 'SAML_TOKEN',</span>
|
|
<span class="sd"> 'signatureAlgorithm': <ALGORITHM>,</span>
|
|
<span class="sd"> 'signature': {</span>
|
|
<span class="sd"> 'samlToken': <SAML_TOKEN>,</span>
|
|
<span class="sd"> 'value': <DIGEST></span>
|
|
<span class="sd"> }</span>
|
|
<span class="sd"> 'timestamp': {</span>
|
|
<span class="sd"> 'created': '2012-10-26T12:24:18.941Z',</span>
|
|
<span class="sd"> 'expires': '2012-10-26T12:44:18.941Z',</span>
|
|
<span class="sd"> }</span>
|
|
<span class="sd"> }</span>
|
|
<span class="sd"> """</span>
|
|
<span class="k">if</span> <span class="n">input_message</span> <span class="ow">is</span> <span class="bp">None</span><span class="p">:</span>
|
|
<span class="k">return</span>
|
|
|
|
<span class="c"># process only if the schemeId in the request matches the schemeId of</span>
|
|
<span class="c"># this signer</span>
|
|
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">input_message</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">):</span>
|
|
<span class="n">str_input_message</span> <span class="o">=</span> <span class="n">input_message</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">)</span>
|
|
<span class="k">else</span><span class="p">:</span>
|
|
<span class="n">str_input_message</span> <span class="o">=</span> <span class="n">input_message</span>
|
|
<span class="k">if</span> <span class="ow">not</span> <span class="n">SAML_SCHEME_ID</span> <span class="ow">in</span> <span class="n">str_input_message</span><span class="p">:</span>
|
|
<span class="k">return</span> <span class="n">input_message</span>
|
|
|
|
<span class="n">py_obj</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">input_message</span><span class="p">,</span> <span class="n">parse_float</span><span class="o">=</span><span class="n">decimal</span><span class="o">.</span><span class="n">Decimal</span><span class="p">)</span>
|
|
<span class="n">json_params</span> <span class="o">=</span> <span class="n">py_obj</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">PARAMS</span><span class="p">)</span> <span class="c"># pylint: disable=E1103</span>
|
|
<span class="n">ctx</span> <span class="o">=</span> <span class="n">json_params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">EXECUTION_CONTEXT</span><span class="p">)</span>
|
|
|
|
<span class="n">sec_ctx</span> <span class="o">=</span> <span class="n">ctx</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">SECURITY_CONTEXT</span><span class="p">)</span>
|
|
<span class="n">private_key</span> <span class="o">=</span> <span class="n">sec_ctx</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">PRIVATE_KEY</span><span class="p">)</span>
|
|
<span class="n">saml_token</span> <span class="o">=</span> <span class="n">sec_ctx</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">SAML_TOKEN</span><span class="p">)</span>
|
|
<span class="n">jws_algorithm</span> <span class="o">=</span> <span class="n">sec_ctx</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">SIGNATURE_ALGORITHM</span><span class="p">)</span>
|
|
<span class="n">algorithm</span> <span class="o">=</span> <span class="n">algorithm_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">jws_algorithm</span><span class="p">)</span>
|
|
|
|
<span class="n">new_sec_ctx</span> <span class="o">=</span> <span class="p">{}</span>
|
|
<span class="n">new_sec_ctx</span><span class="p">[</span><span class="n">SCHEME_ID</span><span class="p">]</span> <span class="o">=</span> <span class="n">sec_ctx</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">SCHEME_ID</span><span class="p">)</span>
|
|
<span class="n">new_sec_ctx</span><span class="p">[</span><span class="n">TIMESTAMP</span><span class="p">]</span> <span class="o">=</span> <span class="n">_generate_request_timestamp</span><span class="p">()</span>
|
|
<span class="n">new_sec_ctx</span><span class="p">[</span><span class="n">SIGNATURE_ALGORITHM</span><span class="p">]</span> <span class="o">=</span> <span class="n">jws_algorithm</span>
|
|
|
|
<span class="c"># Replace the old security context with the new one</span>
|
|
<span class="k">del</span> <span class="n">ctx</span><span class="p">[</span><span class="n">SECURITY_CONTEXT</span><span class="p">]</span>
|
|
<span class="n">ctx</span><span class="p">[</span><span class="n">SECURITY_CONTEXT</span><span class="p">]</span> <span class="o">=</span> <span class="n">new_sec_ctx</span>
|
|
|
|
<span class="n">pkey</span> <span class="o">=</span> <span class="n">crypto</span><span class="o">.</span><span class="n">load_privatekey</span><span class="p">(</span>
|
|
<span class="n">crypto</span><span class="o">.</span><span class="n">FILETYPE_PEM</span><span class="p">,</span> <span class="n">_prep_private_key</span><span class="p">(</span><span class="n">private_key</span><span class="p">))</span>
|
|
<span class="n">canonical_message</span> <span class="o">=</span> <span class="n">JSONCanonicalizer</span><span class="o">.</span><span class="n">canonicalize_py_obj</span><span class="p">(</span><span class="n">py_obj</span><span class="p">)</span>
|
|
<span class="n">digest</span> <span class="o">=</span> <span class="n">b64encode</span><span class="p">(</span><span class="n">crypto</span><span class="o">.</span><span class="n">sign</span><span class="p">(</span>
|
|
<span class="n">pkey</span><span class="p">,</span> <span class="n">canonical_message</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">),</span> <span class="n">algorithm</span><span class="p">))</span>
|
|
|
|
<span class="n">new_sec_ctx</span><span class="p">[</span><span class="n">SIGNATURE</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="n">SAML_TOKEN</span><span class="p">:</span> <span class="n">saml_token</span><span class="p">,</span>
|
|
<span class="n">DIGEST</span><span class="p">:</span> <span class="n">digest</span><span class="p">}</span>
|
|
<span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">py_obj</span><span class="p">,</span>
|
|
<span class="n">check_circular</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span>
|
|
<span class="n">separators</span><span class="o">=</span><span class="p">(</span><span class="s">','</span><span class="p">,</span> <span class="s">':'</span><span class="p">),</span>
|
|
<span class="n">cls</span><span class="o">=</span><span class="n">DecimalEncoder</span><span class="p">)</span>
|
|
|
|
</div></div>
|
|
<div class="viewcode-block" id="JSONSSOVerifier"><a class="viewcode-back" href="../../../../vmware.vapi.security.html#vmware.vapi.security.sso.JSONSSOVerifier">[docs]</a><span class="k">class</span> <span class="nc">JSONSSOVerifier</span><span class="p">(</span><span class="n">RequestProcessor</span><span class="p">):</span>
|
|
<span class="sd">"""</span>
|
|
<span class="sd"> This class is used to verify the authenticity of the request</span>
|
|
<span class="sd"> message by verifying the digest present in the security context</span>
|
|
<span class="sd"> block.</span>
|
|
<span class="sd"> """</span>
|
|
<div class="viewcode-block" id="JSONSSOVerifier.process"><a class="viewcode-back" href="../../../../vmware.vapi.security.html#vmware.vapi.security.sso.JSONSSOVerifier.process">[docs]</a> <span class="k">def</span> <span class="nf">process</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">input_message</span><span class="p">):</span>
|
|
<span class="sd">"""</span>
|
|
<span class="sd"> Verify the input JSON message.</span>
|
|
|
|
<span class="sd"> For verification, we need 4 things:</span>
|
|
|
|
<span class="sd"> 1. algorithm: extracted from security context</span>
|
|
<span class="sd"> 2. certificate: public key of the principal embedded in the</span>
|
|
<span class="sd"> SAML token is used</span>
|
|
<span class="sd"> 3. digest: value field from signature block</span>
|
|
<span class="sd"> 4. canonical msg: signature block is removed from the request</span>
|
|
<span class="sd"> and the remaining part is canonicalized</span>
|
|
|
|
<span class="sd"> Sample input security context:</span>
|
|
<span class="sd"> {</span>
|
|
<span class="sd"> 'schemeId': 'SAML_TOKEN',</span>
|
|
<span class="sd"> 'signatureAlgorithm': <ALGORITHM>,</span>
|
|
<span class="sd"> 'signature': {</span>
|
|
<span class="sd"> 'samlToken': <SAML_TOKEN>,</span>
|
|
<span class="sd"> 'value': <DIGEST></span>
|
|
<span class="sd"> }</span>
|
|
<span class="sd"> 'timestamp': {</span>
|
|
<span class="sd"> 'created': '2012-10-26T12:24:18.941Z',</span>
|
|
<span class="sd"> 'expires': '2012-10-26T12:44:18.941Z',</span>
|
|
<span class="sd"> }</span>
|
|
<span class="sd"> }</span>
|
|
|
|
<span class="sd"> :type input_message: :class:`str`</span>
|
|
<span class="sd"> :param input_message: Input JSON request message</span>
|
|
<span class="sd"> :rtype: :class:`str`</span>
|
|
<span class="sd"> :return: JSON request message after signature verification</span>
|
|
<span class="sd"> """</span>
|
|
<span class="k">if</span> <span class="ow">not</span> <span class="n">input_message</span><span class="p">:</span>
|
|
<span class="k">return</span>
|
|
|
|
<span class="n">str_input_message</span> <span class="o">=</span> <span class="n">input_message</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">)</span>
|
|
<span class="k">if</span> <span class="ow">not</span> <span class="n">SAML_SCHEME_ID</span> <span class="ow">in</span> <span class="n">str_input_message</span><span class="p">:</span>
|
|
<span class="k">return</span> <span class="n">input_message</span>
|
|
|
|
<span class="n">py_obj</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">input_message</span><span class="p">,</span> <span class="n">parse_float</span><span class="o">=</span><span class="n">decimal</span><span class="o">.</span><span class="n">Decimal</span><span class="p">)</span>
|
|
<span class="n">json_params</span> <span class="o">=</span> <span class="n">py_obj</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">PARAMS</span><span class="p">)</span> <span class="c"># pylint: disable=E1103</span>
|
|
<span class="n">execution_ctx</span> <span class="o">=</span> <span class="n">json_params</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">EXECUTION_CONTEXT</span><span class="p">)</span>
|
|
<span class="n">sec_ctx</span> <span class="o">=</span> <span class="n">execution_ctx</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">SECURITY_CONTEXT</span><span class="p">)</span>
|
|
|
|
<span class="n">signature</span> <span class="o">=</span> <span class="n">sec_ctx</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">SIGNATURE</span><span class="p">)</span>
|
|
<span class="k">del</span> <span class="n">sec_ctx</span><span class="p">[</span><span class="n">SIGNATURE</span><span class="p">]</span>
|
|
|
|
<span class="n">digest</span> <span class="o">=</span> <span class="n">b64decode</span><span class="p">(</span><span class="n">signature</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">DIGEST</span><span class="p">))</span>
|
|
<span class="n">jws_algorithm</span> <span class="o">=</span> <span class="n">sec_ctx</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">SIGNATURE_ALGORITHM</span><span class="p">)</span>
|
|
<span class="n">algorithm</span> <span class="o">=</span> <span class="n">algorithm_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">jws_algorithm</span><span class="p">)</span>
|
|
<span class="n">saml_token</span> <span class="o">=</span> <span class="n">signature</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">SAML_TOKEN</span><span class="p">)</span>
|
|
<span class="n">certificate</span> <span class="o">=</span> <span class="n">_extract_certificate</span><span class="p">(</span><span class="n">saml_token</span><span class="p">)</span>
|
|
|
|
<span class="n">pubkey</span> <span class="o">=</span> <span class="n">crypto</span><span class="o">.</span><span class="n">load_certificate</span><span class="p">(</span>
|
|
<span class="n">crypto</span><span class="o">.</span><span class="n">FILETYPE_PEM</span><span class="p">,</span> <span class="n">_prep_certificate</span><span class="p">(</span><span class="n">certificate</span><span class="p">))</span>
|
|
<span class="n">canonical_message</span> <span class="o">=</span> <span class="n">JSONCanonicalizer</span><span class="o">.</span><span class="n">canonicalize_py_obj</span><span class="p">(</span><span class="n">py_obj</span><span class="p">)</span>
|
|
<span class="n">crypto</span><span class="o">.</span><span class="n">verify</span><span class="p">(</span>
|
|
<span class="n">pubkey</span><span class="p">,</span> <span class="n">digest</span><span class="p">,</span> <span class="n">canonical_message</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">'utf-8'</span><span class="p">),</span> <span class="n">algorithm</span><span class="p">)</span>
|
|
|
|
<span class="n">sec_ctx</span><span class="p">[</span><span class="n">SAML_TOKEN</span><span class="p">]</span> <span class="o">=</span> <span class="n">saml_token</span>
|
|
<span class="n">sec_ctx</span><span class="p">[</span><span class="n">AUTHENTICATED</span><span class="p">]</span> <span class="o">=</span> <span class="bp">True</span>
|
|
<span class="n">sec_ctx</span><span class="p">[</span><span class="n">SIGNATURE_ALGORITHM</span><span class="p">]</span> <span class="o">=</span> <span class="n">jws_algorithm</span>
|
|
|
|
<span class="k">return</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">py_obj</span><span class="p">,</span>
|
|
<span class="n">check_circular</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span>
|
|
<span class="n">separators</span><span class="o">=</span><span class="p">(</span><span class="s">','</span><span class="p">,</span> <span class="s">':'</span><span class="p">),</span>
|
|
<span class="n">cls</span><span class="o">=</span><span class="n">DecimalEncoder</span><span class="p">)</span>
|
|
|
|
</div></div>
|
|
<span class="k">def</span> <span class="nf">_extract_element</span><span class="p">(</span><span class="n">xml</span><span class="p">,</span> <span class="n">element_name</span><span class="p">,</span> <span class="n">namespace</span><span class="p">):</span>
|
|
<span class="sd">"""</span>
|
|
<span class="sd"> An internal method provided to extract an element from the given XML.</span>
|
|
|
|
<span class="sd"> :type xml: :class:`str`</span>
|
|
<span class="sd"> :param xml: The XML string from which the element will be extracted.</span>
|
|
<span class="sd"> :type element_name: :class:`str`</span>
|
|
<span class="sd"> :param element_name: The element that needs to be extracted from the XML.</span>
|
|
<span class="sd"> :type namespace: :class:`dict`</span>
|
|
<span class="sd"> :param namespace: A dict containing the namespace of the element to be</span>
|
|
<span class="sd"> extracted.</span>
|
|
<span class="sd"> :rtype: etree element.</span>
|
|
<span class="sd"> :return: The extracted element.</span>
|
|
<span class="sd"> """</span>
|
|
<span class="k">assert</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">namespace</span><span class="p">)</span> <span class="o">==</span> <span class="mi">1</span><span class="p">)</span>
|
|
<span class="n">result</span> <span class="o">=</span> <span class="n">xml</span><span class="o">.</span><span class="n">xpath</span><span class="p">(</span><span class="s">"//</span><span class="si">%s</span><span class="s">:</span><span class="si">%s</span><span class="s">"</span> <span class="o">%</span> <span class="p">(</span><span class="nb">list</span><span class="p">(</span><span class="n">namespace</span><span class="o">.</span><span class="n">keys</span><span class="p">())[</span><span class="mi">0</span><span class="p">],</span> <span class="n">element_name</span><span class="p">),</span>
|
|
<span class="n">namespaces</span><span class="o">=</span><span class="n">namespace</span><span class="p">)</span>
|
|
<span class="k">if</span> <span class="n">result</span><span class="p">:</span>
|
|
<span class="k">return</span> <span class="n">result</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
|
|
<span class="k">else</span><span class="p">:</span>
|
|
<span class="k">raise</span> <span class="ne">KeyError</span><span class="p">(</span><span class="s">"</span><span class="si">%s</span><span class="s"> does not seem to be present in the XML."</span> <span class="o">%</span>
|
|
<span class="n">element_name</span><span class="p">)</span>
|
|
|
|
|
|
<span class="k">def</span> <span class="nf">_prep_private_key</span><span class="p">(</span><span class="n">private_key</span><span class="p">):</span>
|
|
<span class="sd">"""</span>
|
|
<span class="sd"> Append proper prefix and suffix text to a private key. There is no</span>
|
|
<span class="sd"> standard way for storing certificates. OpenSSL expects the demarcation</span>
|
|
<span class="sd"> text. This method makes sure that the text the markers are present.</span>
|
|
|
|
<span class="sd"> :type text: :class:`str`</span>
|
|
<span class="sd"> :param text: The private key of the service user.</span>
|
|
|
|
<span class="sd"> :rtype: :class:`str`</span>
|
|
<span class="sd"> :return: Normalized private key.</span>
|
|
<span class="sd"> """</span>
|
|
<span class="k">if</span> <span class="ow">not</span> <span class="n">key_regex</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">private_key</span><span class="p">):</span>
|
|
<span class="k">return</span> <span class="s">"""-----BEGIN RSA PRIVATE KEY-----</span>
|
|
<span class="si">%s</span><span class="s"></span>
|
|
<span class="s">-----END RSA PRIVATE KEY-----"""</span> <span class="o">%</span> <span class="n">private_key</span>
|
|
<span class="k">return</span> <span class="n">private_key</span>
|
|
|
|
|
|
<span class="k">def</span> <span class="nf">_prep_certificate</span><span class="p">(</span><span class="n">certificate</span><span class="p">):</span>
|
|
<span class="sd">"""</span>
|
|
<span class="sd"> Append proper prefix and suffix text to a certificate. There is no</span>
|
|
<span class="sd"> standard way for storing certificates. OpenSSL expects the demarcation</span>
|
|
<span class="sd"> text. This method makes sure that the text the markers are present.</span>
|
|
|
|
<span class="sd"> :type text: :class:`str`</span>
|
|
<span class="sd"> :param text: The certificate of the service user.</span>
|
|
|
|
<span class="sd"> :rtype: :class:`str`</span>
|
|
<span class="sd"> :return: Normalized certificate</span>
|
|
<span class="sd"> """</span>
|
|
<span class="k">if</span> <span class="ow">not</span> <span class="n">certificate</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">'-----BEGIN CERTIFICATE-----'</span><span class="p">):</span>
|
|
<span class="k">return</span> <span class="s">"""-----BEGIN CERTIFICATE-----</span>
|
|
<span class="si">%s</span><span class="s"></span>
|
|
<span class="s">-----END CERTIFICATE-----"""</span> <span class="o">%</span> <span class="n">certificate</span>
|
|
<span class="k">return</span> <span class="n">certificate</span>
|
|
|
|
|
|
<span class="k">def</span> <span class="nf">_extract_certificate</span><span class="p">(</span><span class="n">hok_token</span><span class="p">):</span>
|
|
<span class="sd">"""</span>
|
|
<span class="sd"> Extract Certificate of the principal from Holder of Key SAML token</span>
|
|
|
|
<span class="sd"> :type hok_token: :class:`str`</span>
|
|
<span class="sd"> :param hok_token: Holder of key SAML token</span>
|
|
<span class="sd"> :rtype: :class:`str`</span>
|
|
<span class="sd"> :return: Certificate of the principal</span>
|
|
<span class="sd"> """</span>
|
|
<span class="n">xml</span> <span class="o">=</span> <span class="n">etree</span><span class="o">.</span><span class="n">fromstring</span><span class="p">(</span><span class="n">hok_token</span><span class="p">)</span>
|
|
<span class="n">subject</span> <span class="o">=</span> <span class="n">_extract_element</span><span class="p">(</span>
|
|
<span class="n">xml</span><span class="p">,</span>
|
|
<span class="s">'SubjectConfirmationData'</span><span class="p">,</span>
|
|
<span class="p">{</span><span class="s">'saml2'</span><span class="p">:</span> <span class="s">'urn:oasis:names:tc:SAML:2.0:assertion'</span><span class="p">})</span>
|
|
<span class="n">xml_certificate</span> <span class="o">=</span> <span class="n">subject</span><span class="o">.</span><span class="n">getchildren</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">getchildren</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">getchildren</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span>
|
|
<span class="k">return</span> <span class="n">xml_certificate</span><span class="o">.</span><span class="n">text</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">'</span><span class="se">\\</span><span class="s">n'</span><span class="p">,</span> <span class="s">'</span><span class="se">\n</span><span class="s">'</span><span class="p">)</span>
|
|
|
|
|
|
<span class="k">def</span> <span class="nf">_generate_request_timestamp</span><span class="p">():</span>
|
|
<span class="sd">"""</span>
|
|
<span class="sd"> Generate a timestamp for the request. This will be embedded in the security</span>
|
|
<span class="sd"> context of the request to protect it against replay attacks</span>
|
|
|
|
<span class="sd"> :rtype: :class:`dict`</span>
|
|
<span class="sd"> :return: Timestamp block that can be inserted in security context</span>
|
|
<span class="sd"> """</span>
|
|
<span class="n">created_dt</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">utcnow</span><span class="p">()</span>
|
|
<span class="n">offset</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">timedelta</span><span class="p">(</span><span class="n">minutes</span><span class="o">=</span><span class="n">REQUEST_VALIDITY</span><span class="p">)</span>
|
|
<span class="n">created</span> <span class="o">=</span> <span class="n">DateTimeConverter</span><span class="o">.</span><span class="n">convert_from_datetime</span><span class="p">(</span><span class="n">created_dt</span><span class="p">)</span>
|
|
<span class="n">expires</span> <span class="o">=</span> <span class="n">DateTimeConverter</span><span class="o">.</span><span class="n">convert_from_datetime</span><span class="p">(</span><span class="n">created_dt</span> <span class="o">+</span> <span class="n">offset</span><span class="p">)</span>
|
|
<span class="k">return</span> <span class="p">{</span><span class="n">EXPIRES</span><span class="p">:</span> <span class="n">expires</span><span class="p">,</span> <span class="n">CREATED</span><span class="p">:</span> <span class="n">created</span><span class="p">}</span>
|
|
</pre></div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="sphinxsidebar">
|
|
<div class="sphinxsidebarwrapper">
|
|
<div id="searchbox" style="display: none">
|
|
<h3>Quick search</h3>
|
|
<form class="search" action="../../../../search.html" method="get">
|
|
<input type="text" name="q" />
|
|
<input type="submit" value="Go" />
|
|
<input type="hidden" name="check_keywords" value="yes" />
|
|
<input type="hidden" name="area" value="default" />
|
|
</form>
|
|
<p class="searchtip" style="font-size: 90%">
|
|
Enter search terms or a module, class or function name.
|
|
</p>
|
|
</div>
|
|
<script type="text/javascript">$('#searchbox').show(0);</script>
|
|
</div>
|
|
</div>
|
|
<div class="clearer"></div>
|
|
</div>
|
|
<div class="related">
|
|
<h3>Navigation</h3>
|
|
<ul>
|
|
<li class="right" style="margin-right: 10px">
|
|
<a href="../../../../genindex.html" title="General Index"
|
|
>index</a></li>
|
|
<li class="right" >
|
|
<a href="../../../../py-modindex.html" title="Python Module Index"
|
|
>modules</a> |</li>
|
|
<li><a href="../../../../index.html">vSphere Automation SDK for Python 6.5.0 documentation</a> »</li>
|
|
<li><a href="../../../index.html" >Module code</a> »</li>
|
|
</ul>
|
|
</div>
|
|
<div class="footer">
|
|
© Copyright 2014, VMware, Inc..
|
|
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.1.3.
|
|
</div>
|
|
</body>
|
|
</html> |