Example #1
0
def complete(token=None):
    """

    This function is called asynchornously via AJAX by the batch signature page
    for each document being signed. It receives the tokne, that identifies the
    signature process. We'll call REST PKI to complete this signature and return
    a JSON with the saved filename so that the page can render a link to it.

    """

    # Get an instance of the CadesSignatureFinisher class, responsible for
    # completing the signature process.
    signature_finisher = CadesSignatureFinisher(get_restpki_client())

    # Set the token.
    signature_finisher.token = token

    # Call the finish() method, which finalizes the signature process.The
    # return value is the CMS content.
    result = signature_finisher.finish()

    # At this point, you'd typically store the signed PDF on your database.
    # For demonstration purposes, we'll store the CMS on a temporary folder
    # publicly accessible and render a link to it.

    create_app_data()  # Guarantees that "app data" folder exists.
    filename = '%s.p7s' % (str(uuid.uuid4()))
    result.write_to_file(
        os.path.join(current_app.config['APPDATA_FOLDER'], filename))

    return jsonify(filename)
Example #2
0
def get_visual_representation():
    """

    This function is called by PAdES samples. It contains an example of
    signature visual representation. This is only in a separate function in
    order to organize the various examples.

    """

    # Create a visual representation.
    visual_representation = {

        'text': {

            # For a full list of the supported tags, see:
            # https://github.com/LacunaSoftware/RestPkiSamples/blob/master/PadesTags.md
            'text': 'Signed by {{name}} ({{national_id}})',
            'fontSize': 13.0,
            # Specify that the signing time should also be rendered.
            'includeSigningTime': True,
            # Optionally set the horizontal alignment of the text ('Left' or
            # 'Right'), if not set the default is 'Left'.
            'horizontalAlign': 'Left',
            # Optionally set the container within the signature rectangle on
            # which to place the text. By default, the text can occupy the
            # entire rectangle (how much of the rectangle the text will actually
            # fill depends on the length and font size). Below, we specify that
            # the text should respect a right margin of 1.5 cm.
            'container': {
                'left': 0.2,
                'top': 0.2,
                'right': 0.2,
                'bottom': 0.2
            }
        },
        'image': {

            # We'll use as background the image static/PdfStamp.png
            'resource': {
                'content': b64encode(get_pdf_stamp_content()),
                'mimeType': 'image/png'
            },
            # Align the image to the right horizontally.
            'horizontalAlign': 'Right',
            # Align the image to the center vertically.
            'verticalAlign': 'Center'
        },
    }

    # Position of the visual representation. We get the footnote position preset
    # and customize it.
    visual_positioning = \
        PadesVisualPositioningPresets.get_footnote(get_restpki_client())
    visual_positioning['auto']['container']['height'] = 4.94
    visual_positioning['auto']['signatureRectangleSize']['width'] = 8.0
    visual_positioning['auto']['signatureRectangleSize']['height'] = 4.94
    visual_representation['position'] = visual_positioning

    return visual_representation
Example #3
0
def full():
    """

    This function initiates a XML element signature using REST PKI and renders
    the signature page. The full XML signature is recommended in cases which
    there is a need to sign the whole XML file.

    """

    try:

        # Get an instance of the FullXmlSignatureStarter class, responsible for
        # receiving the signature elements and start the signature process.
        signature_starter = FullXmlSignatureStarter(get_restpki_client())

        # Set the XML to be signed, a sample XML Document.
        signature_starter.set_xml_to_sign(get_sample_xml_document_path())

        # Set the location on which to insert the signature node. If the
        # location is not specified, the signature will appended to the root
        # element (which is most usual with enveloped signatures).
        nsm = NamespaceManager()
        nsm.add_namespace('ls', 'http://www.lacunasoftware.com/sample')
        signature_starter.set_signature_element_location(
            '//ls:signaturePlaceholder', XmlInsertionOptions.APPEND_CHILD, nsm)

        # Set the signature policy.
        signature_starter.signature_policy = \
            StandardSignaturePolicies.XADES_BES

        # Set the security context to be used to determine trust in the
        # certificate chain. We have encapsulated the security context choice on
        # util.py.
        signature_starter.security_context = get_security_context_id()

        # Call the start_with_webpki() method, which initiates the signature.
        # This yields the token, a 43-character case-sensitive URL-safe string,
        # which identifies this signature process. We'll use this value to call
        # the signWithRestPki() method on the Web PKI component (see
        # signature-form.js javascript) and also to complete the signature after
        # the form is submitted (see method pades_signature_action()). This
        # should not be mistaken with the API access token.
        result = signature_starter.start_with_webpki()

        # The token acquired above can only be used for a single signature
        # attempt. In order to retry the signature it is necessary to get a new
        # token. This can be a problem if the user uses the back button of the
        # browser, since the browser might show a cached page that we rendered
        # previously, with a now stale token. To prevent this from happen, we
        # force page expiration through HTTP headers to prevent caching of the
        # page.
        response = make_response(
            render_template('xml_signature/full.html', token=result.token))
        response.headers = get_expired_page_headers()
        return response

    except Exception as e:
        return render_template('error.html', msg=e)
def action():
    """

    This view function receives the form submission from the template
    authentication/index.html. We'll call REST PKI to validate the
    authentication.

    """

    try:

        # Get the token for this authentication (rendered in a hidden input
        # field, see authentication/index.html template).
        token = request.form['token']

        # Get an instance of the Authentication class.
        auth = get_restpki_client().get_authentication()

        # Call the complete_with_webpki() method with the token, which finalizes
        # the authentication process. The call yields a ValidationResults
        # object, which denotes whether the authentication was successful or not
        # (we'll use it to render the page accordingly, see below).
        result = auth.complete_with_webpki(token)

        vr = result.validation_results

        if not vr.is_valid:
            # If the authentication as not successful, we render a page showing
            # what went wrong
            vr_html = str(vr)
            vr_html = vr_html.replace('\n', '<br/>')
            vr_html = vr_html.replace('\t', '&nbsp;&nbsp;&nbsp;&nbsp;')

            return render_template('authentication_restpki/failed.html',
                                   vr_html=vr_html)

        # At this point, you have assurance that the certificate is valid
        # according to the SecurityContext specified on the method
        # start_with_webpki() and that the user is indeed the certificate's
        # subject. Now, you'd typically query your database for a user that
        # matches one of the certificate's fields, such as
        # user_cert.emailAddress or user_cert.pki_brazil.cpf (the actual
        # field to be used as key depends on your application's business
        # logic) and set the user as authenticated with whatever web
        # security framework your application uses. For demonstration
        # purposes, we'll just render the user's certificate information.
        user_cert = result.certificate

        return render_template('authentication_restpki/success.html',
                               user_cert=user_cert)

    except Exception as e:
        return render_template('error.html', msg=e)
Example #5
0
def element():
    """

    This function initiates a XML element signature using REST PKI and renders
    the signature page. The XML element signature is recommended in cases which
    there is a need to sign a specific element of a XML.

    """

    # Instantiate the XmlElementSignatureStarter class, responsible for
    # receiving the signature elements and start the signature process.
    try:
        signature_starter = XmlElementSignatureStarter(get_restpki_client())

        # Set the XML to be signed, a sample XML Document.
        signature_starter.set_xml_to_sign(get_sample_nfe_path())

        # Set the ID of the element to be signed.
        signature_starter.to_sign_element_id = \
            'NFe35141214314050000662550010001084271182362300'

        # Set the signature policy.
        signature_starter.signature_policy = \
            StandardSignaturePolicies.NFE_PADRAO_NACIONAL

        # Set a security context to be used to determine trust in the
        # certificate chain. We have encapsulated the security context choice on
        # util.py.
        signature_starter.security_context = get_security_context_id()

        # Call the start_with_webpki() method, which initiates the signature.
        # This yields the token, a 43-character case-sensitive URL-safe string,
        # which identifies this signature process. We'll use this value to call
        # the signWithRestPki() method on the Web PKI component (see
        # signature-form.js javascript) and also to complete the signature after
        # the form is submitted (see method action()). This should not be
        # mistaken with the API access token.
        result = signature_starter.start_with_webpki()

        # The token acquired above can only be used for a single signature
        # attempt. In order to retry the signature it is necessary to get a new
        # token. This can be a problem if the user uses the back button of the
        # browser, since the browser might show a cached page that we rendered
        # previously, with a now stale token. We force page expiration through
        # HTTP headers to prevent caching of the page.
        response = make_response(
            render_template('xml_signature/element.html', token=result.token))
        response.headers = get_expired_page_headers()
        return response

    except Exception as e:
        return render_template('error.html', msg=e)
Example #6
0
def start(file_id=None):
    """

    This function is called asynchonously via AJAX by the batch signature page
    for each document being signed. It receives the ID of the document and
    initiates a CAdES signature using REST PKI and returns a JSON with the
    token, which identifies this signature process, to be used in the next
    signature steps (see batch-signature-form.js).

    """

    # Get an instantiate of the CadesSignatureStarter class, responsible for
    # receiving the signature elements and start the signature process.
    signature_starter = CadesSignatureStarter(get_restpki_client())

    # Set the document to be signed based on its ID.
    signature_starter.set_file_to_sign_path(get_sample_batch_doc_path(file_id))

    # Set the signature policy.
    signature_starter.signature_policy = \
        StandardSignaturePolicies.PKI_BRAZIL_CADES_ADR_BASICA

    # Set a security context. We have encapsulated the security context
    # choice on util.py.
    signature_starter.security_context = get_security_context_id()

    # Optionally, set whether the content should be encapsulated in the
    # resulting CMS. If this parameter is ommitted, the following rules
    # apply:
    # - If no CmsToCoSign is given, the resulting CMS will include the
    # content.
    # - If a CmsToCoSign is given, the resulting CMS will include the
    # content if and only if the CmsToCoSign also includes the content.
    #
    signature_starter.encapsulate_content = True

    # Call the start_with_webpki() method, which initiates the signature.
    # This yields the token, a 43-character case-sensitive URL-safe string,
    # which identifies this signature process. We'll use this value to call
    # the signWithRestPki() method on the Web PKI component (see
    # signature-form.js) and also to complete the signature after
    # the form is submitted (see method action()). This should not be
    # mistaken with the API access token.
    result = signature_starter.start_with_webpki()

    # Return a JSON with the token obtained from REST PKI (the page will use
    # jQuery to decode this value).
    return jsonify(result.token)
Example #7
0
def action():
    """

    This method receives the form submission from the template
    cades-signature/index.html. We'll call REST PKI to complete the signature.

    """

    try:
        # Get the token for this signature (rendered in a hidden input field,
        # see cades-signature/index.html template).
        token = request.form['token']

        # Get an instance of the CadesSignatureFinisher class, responsible for
        # completing the signature process.
        signature_finisher = CadesSignatureFinisher(get_restpki_client())

        # Set the token.
        signature_finisher.token = token

        # Call the finish() method, which finalizes the signature process.The
        # return value is the CMS content.
        result = signature_finisher.finish()

        # Get information about the certificate used by the user to sign the
        # file.This method must only be called after calling the finish()
        # method.
        signer_cert = result.certificate

        # At this point, you'd typically store the signed PDF on your database.
        # For demonstration purposes, we'll store the CMS on a temporary folder
        # publicly accessible and render a link to it.

        create_app_data()  # Guarantees that "app data" folder exists.
        filename = '%s.p7s' % (str(uuid.uuid4()))
        result.write_to_file(
            os.path.join(current_app.config['APPDATA_FOLDER'], filename))

        return render_template('cades_signature_restpki/complete.html',
                               signer_cert=signer_cert,
                               cms_file=filename)

    except Exception as e:
        return render_template('error.html', msg=e)
Example #8
0
def action():
    """

    This function receives the form submission from the template
    xml-signature/index.html. We'll call REST PKI to complete the signature.

    """

    try:

        # Get the token for this signature. (rendered in a hidden input field, see
        # xml-signature/index.html template)
        token = request.form['token']

        # Instantiate the XmlSignatureFinisher class, responsible for completing
        # the signature process.
        signature_finisher = XmlSignatureFinisher(get_restpki_client())

        # Set the token.
        signature_finisher.token = token

        # Call the finish() method, which finalizes the signature process and
        # returns the signed XML.
        result = signature_finisher.finish()

        # Get information about the certificate used by the user to sign the file.
        # This method must only be called after calling the finish() method.
        signer_cert = result.certificate

        # At this point, you'd typically store the signed PDF on your database. For
        # demonstration purposes, we'll store the XML on a temporary folder publicly
        # accessible and render a link to it.

        create_app_data()  # Guarantees that "app data" folder exists.
        filename = '%s.xml' % (str(uuid.uuid4()))
        result.write_to_file(
            os.path.join(current_app.config['APPDATA_FOLDER'], filename))

        return render_template('xml_signature/action.html',
                               filename=filename,
                               signer_cert=signer_cert)

    except Exception as e:
        return render_template('error.html', msg=e)
Example #9
0
def start(file_id=None):
    """

    This function is called asynchonously via AJAX by the batch signature page
    for each document being signed. It receives the ID of the document and
    initiates a PAdES signature using REST PKI and returns a JSON with the
    token, which identifies this signature process, to be used in the next
    signature steps (see batch-signature-form.js).

    """

    # Get an instantiate of the PadesSignatureStarter class, responsible for
    # receiving the signature elements and start the signature process.
    signature_starter = PadesSignatureStarter(get_restpki_client())

    # Set the document to be signed based on its ID.
    signature_starter.set_pdf_to_sign(get_sample_batch_doc_path(file_id))

    # Set the signature policy.
    signature_starter.signature_policy = \
        StandardSignaturePolicies.PADES_BASIC

    # Set a security context to determine trust in the certificate chain. We
    # have encapsulated the security context choice on util.py.
    signature_starter.security_context = get_security_context_id()

    # Set the visual representation for the signature. We have encapsulated
    # this code (on util-pades.py) to be used on various PAdES examples.
    signature_starter.visual_representation = \
        PadesVisualElementsRestPki.get_visual_representation()

    # Call the start_with_webpki() method, which initiates the signature.
    # This yields the token, a 43-character case-sensitive URL-safe string,
    # which identifies this signature process. We'll use this value to call
    # the signWithRestPki() method on the Web PKI component (see
    # signature-form.js) and also to complete the signature after
    # the form is submitted (see method action()). This should not be
    # mistaken with the API access token.
    result = signature_starter.start_with_webpki()

    # Return a JSON with the token obtained from REST PKI (the page will use
    # jQuery to decode this value).
    return jsonify(result.token)
Example #10
0
def index():
    """

    This view function initiates an authentication with REST PKI and renders
    the authentication page.

    """

    try:

        # Get an instance of the Authentication class.
        auth = get_restpki_client().get_authentication()

        # Call the start_with_webpki() method, which initiates the
        # authentication. This yields the "token", a 22-character case-sensitive
        # URL-safe string, which represents this authentication process. We'll
        # use this value to call the signWithRestPki() method on the Web PKI
        # component (see signature-form.js) and also to call the
        # complete_with_webpki() method on the route /authentication/action.
        # This should not be mistaken with the API access token. We have
        # encapsulated the security context choice on util.py.
        token = auth.start_with_webpki(get_security_context_id())

        # The token acquired above can only be used for a single
        # authentication. In order to retry authenticating it is necessary to
        # get a new token. This can be a problem if the user uses the back
        # button of the browser, since the browser might show a cached page that
        # we rendered previously, with a now stale token. To prevent this from
        # happening, we force page expiration through HTTP headers to prevent
        # caching of the page.
        response = make_response(
            render_template('authentication/index.html', token=token))
        response.headers = get_expired_page_headers()
        return response

    except Exception as e:
        return render_template('error.html', msg=e)
Example #11
0
def index(file_to_sign=None, file_to_cosign=None):
    """

    This function initiates a CAdES signature using REST PKI and renders the
    signature page.

    All CAdES signature examples converge to this action, but with different
    URL arguments:

        1. Signature with a server file               : no arguments filled
        2. Signature with a file uploaded by the user : "******" filled
        3. Co-signature of a previously signed CMS    : "cmsfile" filled

    """

    try:

        # Get an instantiate of the CadesSignatureStarter class, responsible for
        # receiving the signature elements and start the signature process.
        signature_starter = CadesSignatureStarter(get_restpki_client())

        if file_to_cosign is not None:
            # If the URL argument "cmsfile" is filled, the user has asked to
            # co-sign a previously signed CMS. We'll set the path to the CMS to
            # be co-signed, which was previously saved in the "app-data" folder
            # by the action() step. Note two important things:
            #
            #   1. The CMS to be co-signed must be set using the method
            #      "set_cms_to_cosign", not the method "set_file_to_sign".
            #
            #   2. Since we're creating CMSs with encapsulated content (see call
            #      to encapsulated_content property below), we don't need to set
            #      the content to be signed, REST PKI will get the content from
            #      the CMS being co-signed.
            #
            signature_starter.set_cms_to_cosign_path(
                '%s/%s' %
                (current_app.config['APPDATA_FOLDER'], file_to_cosign))
        else:
            # If the URL argument "userfile" is filled, it means the user was
            # redirected here by "upload" view (signature with file uploaded by
            # user). We'll set the path of the file to be signed, which was
            # saved in the app_data folder by "upload" view.
            signature_starter.set_file_to_sign_path(
                '%s/%s' % (current_app.config['APPDATA_FOLDER'], file_to_sign))

        # Set the signature policy.
        signature_starter.signature_policy =\
            StandardSignaturePolicies.PKI_BRAZIL_CADES_ADR_BASICA

        # Set a security context to be used to determine trust in the
        # certificate chain. We have encapsulated the security context choice on
        # util.py.
        signature_starter.security_context = get_security_context_id()

        # Optionally, set whether the content should be encapsulated in the
        # resulting CMS. If this parameter is ommitted, the following rules
        # apply:
        #
        # - If no CmsToCoSign is given, the resulting CMS will include the
        # content.
        # - If a CmsToCoSign is given, the resulting CMS will include the
        # content if and only if the CmsToCoSign also includes the content.
        #
        signature_starter.encapsulate_content = True

        # Call the start_with_webpki() method, which initiates the signature.
        # This yields the token, a 43-character case-sensitive URL-safe string,
        # which identifies this signature process. We'll use this value to call
        # the signWithRestPki() method on the Web PKI component (see
        # signature-form.js) and also to complete the signature after
        # the form is submitted (see method action()). This should not be
        # mistaken with the API access token.
        result = signature_starter.start_with_webpki()

        # The token acquired above can only be used for a single signature
        # attempt. In order to retry the signature it is necessary to get a
        # new token. This can be a problem if the user uses the back button of
        # the browser, since the browser might show a cached page that we
        # rendered previously, with a now stale token. To prevent this from
        # happening, we call the method get_expired_page_headers(). To prevent
        # this from happen, we force page expiration through HTTP headers to
        # prevent caching of the page.
        response = make_response(
            render_template('cades_signature_restpki/index.html',
                            token=result.token))

        get_expired_page_headers(response.headers)
        return response

    except Exception as e:
        return render_template('error.html', msg=e)
Example #12
0
def index(userfile=None):
    """

    This function initiates a PAdES signature using REST PKI and renders the
    signature page.

    Both PAdES signature examples, with a server file and with a file uploaded
    by the user, converge to this function. The difference is that, when the
    file is uploaded by the user, the function is called with a URL argument
    named "userfile".

    """

    try:

        # Get an instantiate of the PadesSignatureStarter class, responsible for
        # receiving the signature elements and start the signature process.
        signature_starter = PadesSignatureStarter(get_restpki_client())

        # If the URL argument "userfile" is filled, it means the user was
        # redirected here by "upload" view (signature with file uploaded by
        # user). We'll set the path of the file to be signed, which was saved
        # in the app_data folder by "upload" view.
        if userfile is not None:
            signature_starter.set_pdf_to_sign(
                '%s/%s' % (current_app.config['APPDATA_FOLDER'], userfile))
        else:
            signature_starter.set_pdf_to_sign(get_sample_doc_path())

        # Set the signature policy.
        signature_starter.signature_policy =\
            StandardSignaturePolicies.PADES_BASIC

        # Set a security context to be used to determine trust in the
        # certificate chain. We have encapsulated the security context choice on
        # util.py.
        signature_starter.security_context = get_security_context_id()

        # Set the visual representation for the signature. We have encapsulated
        # this code (on util-pades.py) to be used on various PAdES examples.
        signature_starter.visual_representation = get_visual_representation()

        # Call the start_with_webpki() method, which initiates the signature.
        # This yields the token, a 43-character case-sensitive URL-safe string,
        # which identifies this signature process. We'll use this value to call
        # the signWithRestPki() method on the Web PKI component (see
        # signature-form.js javascript) and also to complete the signature after
        # the form is submitted (see method pades_signature_action()). This
        # should not be mistaken with the API access token.
        result = signature_starter.start_with_webpki()

        # The token acquired above can only be used for a single signature
        # attempt. In order to retry the signature it is necessary to get a new
        # token. This can be a problem if the user uses the back button of the
        # browser, since the browser might show a cached page that we rendered
        # previously, with a now stale token. To prevent this from happen, we
        # force page expiration through HTTP headers to prevent caching of the
        # page.
        response = make_response(render_template('pades_signature/index.html',
                                                 token=result.token,
                                                 userfile=userfile))
        response.headers = get_expired_page_headers()
        return response

    except Exception as e:
        return render_template('error.html', msg=e)