Integrating openid connect with opensearch throws an 401 unauthroised error , using azure ad as our idp

Versions (relevant - OpenSearch/Dashboard/Server OS/Browser):

opensearch version : 2.3.0
opensearch dasboard : 2.3.0
Browser : Chrome

Describe the issue:
After configuring openid with opensearch it throws an error after entering the credentials ( using azure micorsoft sigin - azure ad ( idp ).

At first after configuration i was able to login succesfully but the permission were not retained ( had a complete new dashboard in place ). But after restarting the dashboard it throws an 401 error andn from then on I am not able to get to dashboard.

Configuration:

config.yml

   authc: 
     basic_internal_auth_domain:
        description: "Authenticate via HTTP Basic against internal users database"
        http_enabled: true
        transport_enabled: true
        order: 1
        http_authenticator:
          type: basic
          challenge: false
        authentication_backend:
          type: internal

      openid_auth_domain:
        order: 0
        http_enabled: true
        transport_enabled: true
        http_authenticator:
          type: openid
          challenge: false
          config:
             roles_key: roles
             subject_key: email
             openid_connect_url: https://login.microsoftonline.com/<tenantid>/v2.0/.well-known/openid-configuration
        authentication_backend:
          type: noop

opensearch_dashboard.yml

opensearch_security.auth.type: openid
opensearch_security.openid.client_id: “id”
opensearch_security.openid.client_secret: secret_id
opensearch_security.openid.scope: “openid email profile offline_access User.Read”

opensearch_security.openid.base_redirect_url: https:/
opensearch_security.openid.connect_url: https://login.microsoftonline.com//v2.0/.well-known/openid-configuration

Note : after each change in any config file, I had run securyadmin.sh script

Relevant Logs or Screenshots:

could anyone please help me with this, I have been stuck with days on this now.

Can anyone help me with this please
I am open to provode any necessary information required for troubleshooting

@raj1209 Have you found a solution to your issue?
If not, could you share how did you configure the roles in Azure?
Did you map these roles as backend roles in OpenSearch security plugin?

Hi,
No I could not find the solution to it
I have not configured any roles on the Azure side, since we intend to use SSO only for Authentication and not for Authorization.

@raj1209 In that case did you map the authenticated user to the role in OpenSearch security?

The user role is admin with all admin rights.

role_mapping

all_access:
reserved: false
backend_roles:

  • “admin”
    description: “Maps admin to all_access”

@raj1209 If you’re using Azure only for authentication, then you must use roles_binding.yml to bind role with Azure user and not the backend role.

i.e.

my_custom_role:
  reserved: false
  hidden: false
  backend_roles: []
  hosts: []
  users:
  - "Azure_user1"
  - "Azure_user2"
1 Like

Hi @pablo, just to have a clear information

Firstly, can we user Azure only for authentication ?

  • I have configured all the above and I can login to opensearch now but no index or backend role is mapped to user but that’s not the case.
    user who have signed with Azure already have an admin access in OpenSearch but if user logs in through username and password, its working as expected.

Secondly, I have not configured any user / group / roles on Azure end just taken the required credentials like secrent id, client id, url and etc.

Here’s the requirement we had it in mind please let us know if this use case is possible.

suppose 3 user already exist in Opensearch ( A, B, C ) already have some some roles mapped to them ( A - role1, B - role2, C - role 3 )
when user A click “sing in with Single sign on” on web page, he should be able to sign in ( which is working in my case ) and have the role ( role1) attached to it ( not working in my case ).

or is it mandatory to have groups created in Azure application and create a backend role with same as one created in Azure and map it.

we want to avoid creating like groups or roles in Azure.

is this possible, please let us know. Thank you

@raj1209 As per my previous comments, you can use Azure for authentication only if you wish. However, in this scenario, you must map individual users to the OpenSearch roles in roles_mapping.yml to assign permissions.

What is your expected behaviour? Are you planning to map all the users individually?

I’m concerned about already existing user, I have 40 user who have been already mapped to some role in OpenSearch.
They are signing in with SSO → authenticating with Azure credentials and they are able to login to OS.
But its shows that they don’t have backend roles assigned and they are not able to view indices or perform any operation.

and that’s not the case when they enter username and password in OpenSearch login

Is this correct way to go or My understanding towards this is wrong.

@raj1209 The missing backend role might be caused by Azure/OpenSearch misconfiguration. If the JWT token sent from Azure is missing the roles, then you won’t see any backend_roles under the authenticated user in OpenSearch Dashboards.

When you use username and password authentication (I assume you’re talking about basicauth), then you use internal users who are mapped to OpenSearch roles. Basicauth doesn’t require backend roles configuration as role mapping is at the OpenSearch level.

Hi,
I do have the same issue.
In my case I create a role admin in azure which is mapped to all all_access role by default in opensearch and got the same 401 error.

all_access:
  reserved: false
  backend_roles:
  - "admin"
  description: "Maps admin to all_access"

@ogulman Could you open a new thread and share the config.yml file?

Did you configure the role in Azure App registrations -> <app> -> App roles

image

and mapped to the user in Enterprise applications -> <app> -> Users and groups?

Hi Paolo,
I’ve create and admin role in azure and map a user than map admin as backend role in all_access role in opensearch and I’m getting 401 errors.
I try to set logging.verbose: true and I don’t see any other useful logs.

config.yml

---

_meta:
  type: "config"
  config_version: 2

config:
  dynamic:
    http:
      anonymous_auth_enabled: false
      xff:
        enabled: false
        internalProxies: '192\.168\.0\.10|192\.168\.0\.11' # regex pattern
        remoteIpHeader:  'x-forwarded-for'
    authc:
      basic_internal_auth_domain:
        description: "Authenticate via HTTP Basic against internal users database"
        http_enabled: true
        transport_enabled: true
        order: 1 # Must set to 1 to prevent logs flooding with warnings
        http_authenticator:
          type: basic
          challenge: false
        authentication_backend:
          type: internal
      openid_auth_domain:
        http_enabled: true
        transport_enabled: true
        order: 0 # Must set to 0 to precede basic authentication or logs will flood with warnings
        http_authenticator:
          type: openid
          challenge: false
          config:
            openid_connect_idp:
              enable_ssl: true # Without this JWT cookie will fail and token won't be passed to engine
              verify_hostnames: false # If SNI certificate is used and hostnames match, set to true
              subject_key: email # Users will be able to login with email and show it as username
              roles_key: roles # Use roles from App registrations, do not set to groups.
              openid_connect_url: https://login.microsoftonline.com/d0ef736e-3u9m-14e5-6810-h6b4645db12c/v2.0/.well-known/openid-configuration
        authentication_backend:
          type: noop # Here we disable authentication backend since we will be using Azure AD for that

opensearch.yml

---
cluster.name: docker-cluster

# Bind to all interfaces because we don't know what IP address Docker will assign to us.
network.host: 0.0.0.0

# # minimum_master_nodes need to be explicitly set when bound on a public IP
# # set to 1 to allow single node clusters
# discovery.zen.minimum_master_nodes: 1

# Setting network.host to a non-loopback address enables the annoying bootstrap checks. "Single-node" mode disables them again.
# discovery.type: single-node

######## Start OpenSearch Security Demo Configuration ########
# WARNING: revise all the lines below before you go into production
plugins.security.ssl.transport.pemcert_filepath: esnode.pem
plugins.security.ssl.transport.pemkey_filepath: esnode-key.pem
plugins.security.ssl.transport.pemtrustedcas_filepath: root-ca.pem
plugins.security.ssl.transport.enforce_hostname_verification: false
plugins.security.ssl.http.enabled: true
plugins.security.ssl.http.pemcert_filepath: esnode.pem
plugins.security.ssl.http.pemkey_filepath: esnode-key.pem
plugins.security.ssl.http.pemtrustedcas_filepath: root-ca.pem
plugins.security.allow_unsafe_democertificates: true
plugins.security.allow_default_init_securityindex: true
plugins.security.authcz.admin_dn:
  - CN=kirk,OU=client,O=client,L=test, C=de
  - "CN=dxkibana.euroware.it,OU=kirk,O=client,L=test,C=de"
plugins.security.audit.type: internal_opensearch
plugins.security.enable_snapshot_restore_privilege: true
plugins.security.check_snapshot_restore_write_privileges: true
plugins.security.restapi.roles_enabled: ["all_access", "security_rest_api_access"]
plugins.security.system_indices.enabled: true
plugins.security.system_indices.indices: [".plugins-ml-config", ".plugins-ml-connector", ".plugins-ml-model-group", ".plugins-ml-model", ".plugins-ml-task", ".plugins-ml-conversation-meta", ".plugins-ml-conver>node.max_local_storage_nodes: 3
######## End OpenSearch Security Demo Configuration ########

openseaarch_dashboards.yml

#opensearch.hosts: [https://localhost:9200]
opensearch.hosts: ["https://opensearch-node1:9200"]
opensearch.ssl.verificationMode: none
opensearch.username: kibanaserver
opensearch.password: kibanaserver
opensearch.requestHeadersWhitelist: [authorization, securitytenant]

opensearch_security.multitenancy.enabled: true
opensearch_security.multitenancy.tenants.preferred: [Private, Global]
opensearch_security.readonly_mode.roles: [kibana_read_only]
# Use this setting if you are running opensearch-dashboards without https
opensearch_security.cookie.secure: false
server.name: opensearch-dashboards
server.host: '0.0.0.0'

opensearch_security.auth.multiple_auth_enabled: true
opensearch_security.auth.type: ["openid", "basicauth"] # This will show basic auth login screen and an OpenID SSO button

#opensearch_security.auth.type: openid
opensearch_security.openid.client_id: pldkk735-47f1-4de4-uj7k-flfe95726v7g
opensearch_security.openid.client_secret: KLf5S~yKDQFPLVJHG70rtjkgh~vf7XjKfQqvkhns
opensearch_security.openid.base_redirect_url: "https://kibana.local.domain:5601"
opensearch_security.openid.connect_url: https://login.microsoftonline.com/d0ef736e-3u9m-14e5-6810-h6b4645db12c/v2.0/.well-known/openid-configuration
logging.verbose: true

@ogulman I’ve tested your configuration and I had no issues with authenticating through Azure IdP.

How do you deploy your cluster?

Hi Pablo,
Thank you for testing it.
I’ve just create a new vm and deploy cluster using docker compose:

version: '3'
services:
  opensearch-node1: # This is also the hostname of the container within the Docker network (i.e. https://opensearch-node1/)
    image: opensearchproject/opensearch:latest
    container_name: opensearch-node1
    restart: unless-stopped
    environment:
      - cluster.name=opensearch-cluster # Name the cluster
      - node.name=opensearch-node1 # Name the node that will run in this container
#      - discovery.seed_hosts=opensearch-node1,opensearch-node2 # Nodes to look for when discovering the cluster
      - discovery.seed_hosts=opensearch-node1 # Nodes to look for when discovering the cluster
#      - cluster.initial_cluster_manager_nodes=opensearch-node1,opensearch-node2 # Nodes eligibile to serve as cluster manager
      - cluster.initial_cluster_manager_nodes=opensearch-node1 # Nodes eligibile to serve as cluster manager
      - bootstrap.memory_lock=true # Disable JVM heap memory swapping
      - "OPENSEARCH_JAVA_OPTS=-Xms2048m -Xmx2048m" # Set min and max JVM heap sizes to at least 50% of system RAM
    ulimits:
      memlock:
        soft: -1 # Set memlock to unlimited (no soft or hard limit)
        hard: -1
      nofile:
        soft: 65536 # Maximum number of open files for the opensearch user - set to at least 65536
        hard: 65536
    volumes:
      - opensearch-data1:/usr/share/opensearch/data # Creates volume called opensearch-data1 and mounts it to the container
      - ./opensearch/custom_config.yml:/usr/share/opensearch/config/opensearch-security/config.yml
      - ./opensearch/log4j2.properties:/usr/share/opensearch/config/log4j2.properties
      - ./opensearch/custom_roles_mapping.yml:/usr/share/opensearch/config/opensearch-security/roles_mapping.yml
    ports:
      - 9200:9200 # REST API
    #  - 9600:9600 # Performance Analyzer
    expose:
      - 9200
      - 9600
    networks:
      - opensearch-net # All of the containers will join the same Docker bridge network
  opensearch-dashboards:
    image: opensearchproject/opensearch-dashboards:latest # Make sure the version of opensearch-dashboards matches the version of opensearch installed on other nodes
    container_name: opensearch-dashboards
    ports:
      - 443:5601 # Map host port 5601 to container port 5601
    expose:
      - "5601" # Expose port 5601 for web access to OpenSearch Dashboards
    environment:
      OPENSEARCH_HOSTS: '["https://opensearch-node1:9200"]' # Define the OpenSearch nodes that OpenSearch Dashboards will query
      SERVER_SSL_ENABLED: "true"
      SERVER_SSL_CERTIFICATE: /usr/share/opensearch-dashboards/config/client-cert.pem
      SERVER_SSL_KEY: /usr/share/opensearch-dashboards/config/client-cert-key.pem
    volumes:
      - ./dashboard/custom_opensearch_dashboards.yml:/usr/share/opensearch-dashboards/config/opensearch_dashboards.yml
      - ./cert/node.pem:/usr/share/opensearch-dashboards/config/client-cert.pem:ro
      - ./cert/node.key:/usr/share/opensearch-dashboards/config/client-cert-key.pem:ro
    networks:
      - opensearch-net

volumes:
  opensearch-data1:
#  opensearch-data2:

networks:
  opensearch-net:

Now I’m getting “ERR_TOO_MANY_REDIRECTS” msg and in the logs I see:

{"type":"log","@timestamp":"2023-11-22T13:22:37Z","tags":["warning","opensearch","opendistro_security"],"pid":1,"message":"Unable to revive connection: https://opensearch-node1:9200/"}
{"type":"log","@timestamp":"2023-11-22T13:22:37Z","tags":["warning","opensearch","opendistro_security"],"pid":1,"message":"No living connections"}
{"type":"log","@timestamp":"2023-11-22T13:22:37Z","tags":["error","plugins","securityDashboards"],"pid":1,"message":"OpenId authentication failed: Error: No Living connections"}

Using local admin auth works fine.

It’s because you’re redirecting to 5601 in the opensearch_dashboards.yml and I think Azure too.
However, your docker-compose exposes 443 instead of 5601.

I’ve start using 443 port, sorry for confusion.
Too many redirects was becouse of wrong config opensearch_dashboards.yml on new vm.
Now I’m getting same logs as before:

{"type":"log","@timestamp":"2023-11-22T13:52:06Z","tags":["debug","http","server","OpenSearchDashboards","cookie-session-storage"],"pid":1,"message":"Error: Unauthorized"}
{"type":"response","@timestamp":"2023-11-22T13:52:06Z","tags":[],"pid":1,"method":"get","statusCode":401,"req":{"url":"/api/v1/configuration/account","method":"get","headers":{"host":"kibana.local.domain","connection":"keep-alive","sec-ch-ua":"\"Google Chrome\";v=\"119\", \"Chromium\";v=\"119\", \"Not?A_Brand\";v=\"24\"","content-type":"application/json","osd-xsrf":"osd-fetch","sec-ch-ua-mobile":"?0","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","osd-version":"2.11.0","sec-ch-ua-platform":"\"Windows\"","accept":"*/*","sec-fetch-site":"same-origin","sec-fetch-mode":"cors","sec-fetch-dest":"empty","referer":"https://kibana.local.domain/app/login?nextUrl=%2F","accept-encoding":"gzip, deflate, br","accept-language":"en-US,en;q=0.9"},"remoteAddress":"192.168.100.100","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","referer":"https://kibana.local.domain/app/login?nextUrl=%2F"},"res":{"statusCode":401,"responseTime":2,"contentLength":9},"message":"GET /api/v1/configuration/account 401 2ms - 9.0B"}
{"type":"response","@timestamp":"2023-11-22T13:52:06Z","tags":[],"pid":1,"method":"get","statusCode":200,"req":{"url":"/ui/logos/opensearch_on_light.svg","method":"get","headers":{"host":"kibana.local.domain","connection":"keep-alive","sec-ch-ua":"\"Google Chrome\";v=\"119\", \"Chromium\";v=\"119\", \"Not?A_Brand\";v=\"24\"","sec-ch-ua-mobile":"?0","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","sec-ch-ua-platform":"\"Windows\"","accept":"image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8","sec-fetch-site":"same-origin","sec-fetch-mode":"no-cors","sec-fetch-dest":"image","referer":"https://kibana.local.domain/app/login?nextUrl=%2F","accept-encoding":"gzip, deflate, br","accept-language":"en-US,en;q=0.9"},"remoteAddress":"192.168.100.100","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","referer":"https://kibana.local.domain/app/login?nextUrl=%2F"},"res":{"statusCode":200,"responseTime":3,"contentLength":9},"message":"GET /ui/logos/opensearch_on_light.svg 200 3ms - 9.0B"}
{"type":"response","@timestamp":"2023-11-22T13:52:06Z","tags":[],"pid":1,"method":"get","statusCode":200,"req":{"url":"/ui/fonts/source_sans_3/SourceSans3-Semibold.ttf.woff2","method":"get","headers":{"host":"kibana.local.domain","connection":"keep-alive","sec-ch-ua":"\"Google Chrome\";v=\"119\", \"Chromium\";v=\"119\", \"Not?A_Brand\";v=\"24\"","origin":"https://kibana.local.domain","sec-ch-ua-mobile":"?0","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","sec-ch-ua-platform":"\"Windows\"","accept":"*/*","sec-fetch-site":"same-origin","sec-fetch-mode":"cors","sec-fetch-dest":"font","referer":"https://kibana.local.domain/app/login?nextUrl=%2F","accept-encoding":"gzip, deflate, br","accept-language":"en-US,en;q=0.9"},"remoteAddress":"192.168.100.100","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","referer":"https://kibana.local.domain/app/login?nextUrl=%2F"},"res":{"statusCode":200,"responseTime":2,"contentLength":9},"message":"GET /ui/fonts/source_sans_3/SourceSans3-Semibold.ttf.woff2 200 2ms - 9.0B"}
{"type":"response","@timestamp":"2023-11-22T13:52:08Z","tags":[],"pid":1,"method":"get","statusCode":302,"req":{"url":"/auth/openid/login","method":"get","headers":{"host":"kibana.local.domain","connection":"keep-alive","sec-ch-ua":"\"Google Chrome\";v=\"119\", \"Chromium\";v=\"119\", \"Not?A_Brand\";v=\"24\"","sec-ch-ua-mobile":"?0","sec-ch-ua-platform":"\"Windows\"","upgrade-insecure-requests":"1","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","sec-fetch-site":"same-origin","sec-fetch-mode":"navigate","sec-fetch-user":"?1","sec-fetch-dest":"document","accept-encoding":"gzip, deflate, br","accept-language":"en-US,en;q=0.9"},"remoteAddress":"192.168.100.100","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"},"res":{"statusCode":302,"responseTime":4,"contentLength":9},"message":"GET /auth/openid/login 302 4ms - 9.0B"}
{"type":"log","@timestamp":"2023-11-22T13:52:08Z","tags":["error","plugins","securityDashboards"],"pid":1,"message":"OpenId authentication failed: Error: Authentication Exception"}
{"type":"response","@timestamp":"2023-11-22T13:52:08Z","tags":[],"pid":1,"method":"get","statusCode":401,"req":{"url":"/auth/openid/login?code=0.AS8AHnHv0GuL5UCXEMTkYo2xLJHE7PvxeORNvg3c3oYGSjuwAAA.AgABAAIAAAAmoFfGtYxvRrNriQdPKIZ-AgDs_wUA9P8MWUoDlh8Cm_vCbxlGawnvA521aBxIEJ1279o0PmokM9wgt2Mix3HoclaFQEEAhocmnOUP0PonMZXs0rfhzxzBnn2fIoEMNKuBUsHmdZQmWcZO_kZBH6s9sP23q0gS8S87aF29GxkjQwsfkH13jjn0WLLPiSAHlmfeGsOQqZu3BuSz8858rISVZe55OjpplXHE8kKaUm1LT9eSOGY3WQceleXOKzcYx7bNeUN80CpgCsrYeOUYE-tKwFZkNqll9MmkOsjVKgVsrzaFi2QksNkJuNSGKxIF7ooEuWm-DBbcEaysuDUk49CUHUjbOkMu0P9pa8FpsG603A39g2cUzxDzsLjBqdW41oj7k2jS_RzrBXOO-qZ8jysfhWXL6f99txdbiJ5hmXxNwsjNkwDinYGmKiBGoskeP5bM7tqb3Y6W4GqeVX71pNTbMq9Sr1t9i6oPpZIN-vQ4HWgK_DRAtevHFdLLKby9hL3Q1VxJl0N74HYf5f-ycfBR9I06HSiJtZXzEV2kFUV2xMt53zwBCsqmJ6Ri8d2dozwK1KKou_MZDW6S0wY4Xyy1iRcKJysjleXn27ZCZ-eh2TNhTzyNlhGN9JN-ttlq1M-J3XHmQ2s51v6nbW3WvxfMSCzO-rGJj3jP3gJrmIwHxnNgW3BYaozBfAwjZssRd8pMXa7-J5NRGJ73N6ftR95HW5auGM9YoDp_-r8U2iRlXXH7cWhItvQAPzMU-w&state=8_kgr4ZpqYAC--Je9A9YbG&session_state=84504e7f-9165-4413-84fa-c7faa149c443","method":"get","headers":{"host":"kibana.local.domain","connection":"keep-alive","upgrade-insecure-requests":"1","user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36","accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7","sec-fetch-site":"cross-site","sec-fetch-mode":"navigate","sec-fetch-user":"?1","sec-fetch-dest":"document","sec-ch-ua":"\"Google Chrome\";v=\"119\", \"Chromium\";v=\"119\", \"Not?A_Brand\";v=\"24\"","sec-ch-ua-mobile":"?0","sec-ch-ua-platform":"\"Windows\"","accept-encoding":"gzip, deflate, br","accept-language":"en-US,en;q=0.9"},"remoteAddress":"192.168.100.100","userAgent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36"},"res":{"statusCode":401,"responseTime":300,"contentLength":9},"message":"GET /auth/openid/login?code=0.AS8AHnHv0GuL5UCXEMTkYo2xLJHE7PvxeORNvg3c3oYGSjuwAAA.AgABAAIAAAAmoFfGtYxvRrNriQdPKIZ-AgDs_wUA9P8MWUoDlh8Cm_vCbxlGawnvA521aBxIEJ1279o0PmokM9wgt2Mix3HoclaFQEEAhocmnOUP0PonMZXs0rfkzxzBnn2fIoEMNKuBUsHmdZQmWcZO_kZBH6s9sP23q0gS8S87yF29GxkjQwsfkH13jjn0WLLPiSAHlmfeGsOQqZu3BuSz8858rISVZe55OjpplXHE8kKaUm1LT9eSOGY3WQcelhXOKzcYx7bNeUN80CpgCsrYeOUYE-tKwFZkNqll9MmkOsjVKgVsrzaFi2QksEkJuNSGKxIF7ooEuWm-GBbcEaysuDUk49CUHUjbOkMu0P9pa8FpsG603A39g2cUzxDzsLjBqdW41oj7k2jS_RzrBXOO-qZ8jysfhWXL6f99txdbiJ5hmXxNwsjNkwDinYGmKiBGoskeP5bM7tqb3Y6W4GqeVX71pNTbMq9Sr1t9i6oPpZIN-vQ4HWgK_DRAtevHFdLLKby9hL3Q1VxJl0N74HYf5f-ycfBR9I06VSiJtZXzEV2kFUV2xMt53zwBCsqmJ6Ri8d2dozwK1KKou_MZDT6S0wY4Xyy1iRcKJysjleXn27ZCZ-eh2TNhTzyNlhGN9JN-ttlq1M-J3XHmQ2w51v6nbW3WvxfMSCzO-rGJj3jP3gJrmIwHxnNgW3BYaozBfAwjZssRd8pMXa7-J5NRGJ73N6ftR95HW5auGM9YoDp_-r8U2iRlXXH7cWhItvQAPzMU-w&state=8_kgr4ZpqYAC--Je9A9YbG&session_state=84504e7f-9165-4413-84fa-c7faa149c443 401 300ms - 9.0B"}