Skip to main content
Woohoo! Qlik Community has won “Best in Class Community” in the 2024 Khoros Kudos awards!
Announcements
Save $600 on Qlik Connect registration! Sign up by Dec. 6 to get an extra $100 off with code CYBERSAVE: REGISTER
cancel
Showing results for 
Search instead for 
Did you mean: 
virilo_tejedor
Creator
Creator

403/XSRF when calling QPS API (iframe mashup code using python inside ;-)

I'm trying to use QPS API to get a ticket for to be used in a Flask web server by using a mashup iframe.
 
When I run the attached code:
 
- It doesn't return me any ticket, it returns a 403 error instead due to XSRF
 
- It offers me a login form despite the wrong ticket (virtual proxy configured to use form authentication)
 
- Once I log in the iframe, it shows the mashup correctly
 
My setup:
 
- Qlik Sense Server Enterprise 2022
 
- Virtual proxy: ( mostly from this video )
 
- Annonymous access mode: no
- Authentication method: Ticket
- Windows authentication pattern: forms
 
- has secure attribute (https): checked
- SameSite attribute (https): None
- Hosts white list: empty (using just one QS server)
 
- I created cert/key/root files exported from the QMC/Certificates (weird, because once it were exported I stopped watching them listed at QMC/Certificates) 
 
- Certificates were converted to .pem using openssl.   "client.pem" file contains both: a private key and a certificate
 
- Engine\Settings.ini configured with:
 
EnableTTL=1
SessionTTL=30
(and extra CR-LF line)
 
 
Why am I receiving this 403 error?  How could I solve it?
 
Why is it still possible to use the mashup whithout any proper ticket?
 
What is the TargetId parameter used for?  I can see it on this node.js example, but I can't see it is being used in the Powershell example.
 
 
The output log:
 
InsecureRequestWarning: Unverified HTTPS request is being made to host 'analytics.mycompany.com'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
  InsecureRequestWarning,
127.0.0.1 - - [13/Jul/2023 11:00:28] "GET / HTTP/1.1" 200 -
QPS_API_URL https://analytics.mycompany.com:4243/qps/testmashup/ticket?xrfkey=123456789abcdef
ticket:  XSRF prevention check failed. Possible XSRF discovered.
response:  <Response [403]>
response.reason:  Forbidden
 
The python code:

 

 

from flask import Flask, render_template_string
import requests

app = Flask(__name__)

QLIK_SENSE_SERVER_DOMAIN='analytics.mycompany.com'

USER_DIRECTORY = 'MYCOMPANYAD'
USER_ID = 'myuser'  # Root Admin user

XRF_KEY = '123456789abcdefg'  # You can change this
PROXY_PREFIX = 'testmashup'  # Your virtual proxy prefix

QPS_API_URL = f"https://{QLIK_SENSE_SERVER_DOMAIN}:4243/qps/{PROXY_PREFIX}/ticket?xrfkey={XRF_KEY}"  
QPS_HEADERS = {   
    'content-type': 'application/json',
    'X-Qlik-xrfkey': XRF_KEY,
    'X-Qlik-user': f'UserDirectory={USER_DIRECTORY};UserId={USER_ID}'
        
}

assert len(XRF_KEY)==16, f'''XRF_KEY ERROR.  XRF_KEY={XRF_KEY} len={len(XRF_KEY)}

XRF_KEY must be alphanumeric and 16 characters length.

See https://community.qlik.com/t5/Integration-Extension-APIs/403-XSRF-when-calling-QPS-API-iframe-mashup-code-using-python/m-p/2093779/highlight/true#M18855 '''



MASHUP_URL = f"https://{QLIK_SENSE_SERVER_DOMAIN}/{PROXY_PREFIX}/extensions/TestMashup/TestMashup.html" 

@app.route('/')
def serve_page():
    ticket = get_ticket(USER_DIRECTORY, USER_ID)
    iframe_src=f"{MASHUP_URL}?QlikTicket={ticket}"
    html = f"""<!DOCTYPE html>
    <html style="height: 100%;">
    
    <body>
    
    <iframe src="{iframe_src}" frameborder="0" scrolling="yes" seamless="seamless" style="display:block; width:100%; height:100vh;"></iframe>
    
    </html>"""
    return render_template_string(html)

def get_ticket(user_directory, user_id):
    payload = {        
        "UserDirectory": user_directory,
        "UserId": user_id,
        "Attributes": []
        # "TargetId": targetId, # what is actually this targetId ???
        
        
    }
    
    
    response = requests.post(QPS_API_URL, headers=QPS_HEADERS, json=payload, \
                              cert=(r'client.pem', \
                                    r'client.pem'), \
                            verify=False)
    
    # response.raise_for_status()  # Raises stored HTTPError, if one occurred.
    ticket = response.text
    
    print("QPS_API_URL", QPS_API_URL)
    print("ticket: ", ticket)
    print("response: ", response)
    print("response.reason: ", response.reason)
    
    return ticket

if __name__ == "__main__":
    app.run(port=8080)

 

 

Labels (2)
1 Solution

Accepted Solutions
Damien_V
Support
Support

Hello @virilo_tejedor 

Why am I receiving this 403 error?  How could I solve it?
> your XRF key is 15 characters, it needs to be an alphanumeric string that is exactly 16 characters
 
Why is it still possible to use the mashup whithout any proper ticket?
> It shouldn't be possible unless you already have an active cookie for that virtual proxy in your browser, did you try to clear cache/cookies from the browser and test?
 
What is the TargetId parameter used for? 
> Qlik Sense will remember what URL you tried to access before getting redirected to the authentication module and store it in memory as an ID, the mapping between the actual URL and the ID is stored in the Qlik Proxy service memory and cannot be seen directly.
If the issue is solved please mark the answer with Accept as Solution.

View solution in original post

2 Replies
Damien_V
Support
Support

Hello @virilo_tejedor 

Why am I receiving this 403 error?  How could I solve it?
> your XRF key is 15 characters, it needs to be an alphanumeric string that is exactly 16 characters
 
Why is it still possible to use the mashup whithout any proper ticket?
> It shouldn't be possible unless you already have an active cookie for that virtual proxy in your browser, did you try to clear cache/cookies from the browser and test?
 
What is the TargetId parameter used for? 
> Qlik Sense will remember what URL you tried to access before getting redirected to the authentication module and store it in memory as an ID, the mapping between the actual URL and the ID is stored in the Qlik Proxy service memory and cannot be seen directly.
If the issue is solved please mark the answer with Accept as Solution.
virilo_tejedor
Creator
Creator
Author

Yes, I changed the XRF_KEY to be 16 character length and it worked like a charm.

I marked your answer as the solution, and modified the code with an assertion, so other people will be able to reuse this code without stumbling with the same issue.

BTW, I checked also that after cleaning qliksense cookies, it doesn't show the mashup. It shows an squared icon (with an X inside) instead.

Thanks a lot @Damien_V  for your help, and for the clarification regarding the TargetId parameter.