Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC] Improved session management #1311

Closed
davidlago opened this issue Jan 31, 2023 · 35 comments
Closed

[RFC] Improved session management #1311

davidlago opened this issue Jan 31, 2023 · 35 comments
Labels
enhancement New feature or request triaged

Comments

@davidlago
Copy link

davidlago commented Jan 31, 2023

What is the problem?

OpenSearch uses cookies for session management. Cookies have a size limit (4Kb). Some extremely large session payloads (think of large SAML assertions) hit this limit and we don't currently have a path forward for those use cases.

Additional problems of the current session management implementation (or feature requests) are captured in the issues below. We should aim to solve for the main problem above, but if in doing so we can kill any of these "birds" with that stone, and they can inform the solution for this one, that would be great. Otherwise, we can tackle those separately:

What options could we consider?

There are may ways to skin this cat, from short term stopgaps to larger overhauls of how we manage sessions in the product.

Filter JWT attributes stored in the cookie

Right now, there are a number of attributes coming from the IdP that we store in the cookie, whether they are needed or not. Providing an allow-list of attributes and storing just these in the cookies will make the 4Kb limit go a longer way.

Use compression

Compressing the cookie payloads could relax the constrain of that 4Kb limit, as text attributes from the session are generally highly compressible (are we doing that today already? if so, disregard this option).

Stitch multiple cookies together

Another relatively low effort fix for this would be to split cookie payloads into several chunks, and stitching them together when we receive them. If we have, say, 4 chunks... would 16Kb be a high enough limit to enable even the most extreme SAML assertions?

Server-side session management

Storing the session in the backend (whether in OpenSearch Dashboards' backend or OpenSearch's), will remove the size limit, and could potentially address some of the shortcomings of using cookies such as sessions carrying over from device to device, or the ability to invalidate sessions from server side, but it adds complexity and potential use cases we need to think about carefully:

Next steps

Let's use this issue to have a discussion of options, trade-offs, and come up with a design for what a new session management strategy should look like.

@davidlago davidlago added enhancement New feature or request untriaged triaged and removed untriaged labels Jan 31, 2023
@expani
Copy link
Contributor

expani commented Feb 3, 2023

My 2 cents.

Server side session management

This seems to be the right direction for a long term fix for limitations like large assertions, excessive roles and opens up the avenue for a lot of other user-behaviour related insights.

In the future different plugins would want to extend this to collect data relevant to their use-case. The design would need to take this into consideration. Time will be a constraint here to solve the pain-point quickly.

JWT Attribute filter

The subject key and roles form the largest portion of the JWT we generate from a SAML Response. These can be filtered to reduce the cookie size.

However, there is a corner case where it can still restrict a user from adopting an approach of having a large number of granular roles for their use-case. This would depend on the existing role hierarchy used by the user.

Stitch multiple cookies together

This could be a viable option in the short term.

The entire storage layer of cookie is currently abstracted using the session_storage interface in Dashboards. A child implementation of the existing cookie storage can be created which handles the breaking and re-creation of one cookie into multiple one's and re-uses the existing logic of cookie management.

  • The storage layer to be used can be made configurable via the security config defaulting to the current one. Thus, it will be non-invasive.
  • RFC 2109 mentions the support of 20 cookies per domain. So, this approach can support most of the use-cases by increasing the number of cookies used for storage.
  • It will also provide enough time to eventually move towards server side session management.

@prabhat-chaturvedi
Copy link

prabhat-chaturvedi commented Feb 4, 2023

IMHO, we should identify that Cookie shall not carry the entire token. Better options are to store in the session storage instead or backend.

Demerits of storing the token in Cookie is that Client has to send this Cookie on each request, and if there are multi-cookie - all the cookies will be sent and impact the throughput of the systems.

For the per the best practices we should decouple this into :

Front-end :
Is just a mechanism to challenge the user to fetch. In case of SAML - facilitates the redirection to IDP.
Front-end should just validate the cookie which was directed by the backend. The cookie is the front-end session management, and technically can have different lifetimes from the backend.

Backend:
1)Security Token Services (STS)
The STS is just a token granting party - internally does a job of Authorization Server and Token Server in the OIDC terminology. Based on the token produced be it SAML, OIDC, Basic, etc., it grants the permission to create a session.
2)Session Management
Can be Cache based, index based or externalised totally. All have their own pros and cons. Ideally can be externalised to something like Redis Cache based approach.

@nibix
Copy link

nibix commented Feb 6, 2023

Regarding "Filter JWT attributes stored in the cookie":

This approach is a bit more complicated as it might sound. The Dashboards plugin would be not able to just filter the JWT attrs, as then the backend would no longer trust these JWTs (due to a wrong signature). To overcome this, some module would need to re-issue JWTs which are trusted by the backend. As this is still just a workaround, I am not sure whether this is worth the effort. Also, as mentioned before, there is the chance that it is actually the roles which blow up the JWT size. So, I don't really think that this approach is suitable.

@davidlago
Copy link
Author

The entire storage layer of cookie is currently abstracted using the session_storage interface in Dashboards. A child implementation of the existing cookie storage can be created which handles the breaking and re-creation of one cookie into multiple one's and re-uses the existing logic of cookie management.

  • The storage layer to be used can be made configurable via the security config defaulting to the current one. Thus, it will be non-invasive.
  • RFC 2109 mentions the support of 20 cookies per domain. So, this approach can support most of the use-cases by increasing the number of cookies used for storage.
  • It will also provide enough time to eventually move towards server side session management.

I like this approach, as the abstraction layer exists already and we can eventually point to what @prabhat-chaturvedi suggests as an externalized storage for sessions (and at that point stop the cutting/stitching).

This is the shortest path to solving the immediate problem while allowing some more time for the larger efforts in Dashboards linked above (some of which might even make things easier to build, like the externalized metadata store).

@prabhat-chaturvedi
Copy link

The externalised storage is the best solution, but we will have similar challenged for the Frontend session management, which is where to store the JWT. If its opaque token which is stored as Key:randomString,Value:JWT, then the frontend can just keep a handle of that randomString which maps to the session identifier.

Otherwise, even when the JWT should be stored in the Frontend, Cookie length issue is must to be solved.
What I pointed above as an immediate alternative was to save the token in the Browser "session storage".

Dashboard frontend, can extract the JWT from the browser session storage was the session is governed by JSESSIONID(or such application managed session cookie) and then populate the JWT in a POST param, header or Cookie which ever best suits the security plugin to validate.

Again emphasising the demerits for using Cookie to store the JWT are:

  1. Cookie is sent on each request making the request bloated
  2. MultiCookie may make the request too heavy, even though there was not much in the request, but the Cookies would have to go to backend.
  3. Cookie has limitations of 4MB, but Session Storage can go upto 10MB or more in some browsers

There were some benefits when the Cookie was relayed directly from Dashboard to Security plugin, but it might just be a big change to make in the exit gate of Dashboard to pull from Session Storage and populate in the ongoing request to plugin.

@peternied
Copy link
Member

Use compression

Seems really cheap and easy to check. While we want to target the end state, this might be able to mitigate the user experience for a couple of impacted clusters while we get there. Has anyone looked into this?

@davidlago
Copy link
Author

davidlago commented Feb 7, 2023

Unless I'm missing something, it does not look like we use cookie compression.

It seems like a reasonable high level estimate of gzip's rate of compression of ASCII text is 1:11 [1]. With the cookie size being limited as per this RFC to 4Kb, that could raise the limit to something like 44Kb of uncompressed ASCII text.

@jimishs, I know you have done some research on use cases around SAML assertions. Do you have a sense for what reasonable upper bound for the cookie size we should consider in this design?

@domruf
Copy link

domruf commented Feb 8, 2023

@nibix regarding "Filter JWT attributes stored in the cookie" the backend trusting the JWT:

At least in my case, the the id_token is the big thing, because it contains all the group memberships.
And AFAIK only the access_token is required for authenticating against the backend. So I think it would help to only store the access_token and not storing the id_token in the cookie.

@nibix
Copy link

nibix commented Feb 10, 2023

@domruf Actually, it is the other way round. The id_token is needed by the OpenSearch backend to determine the user's roles from the group membership and thus their authorization. The access_token, on the other hand, is only meaningful to the OIDC IdP service.

@nibix
Copy link

nibix commented Feb 14, 2023

Besides discussing the workarounds, IMHO, we should also have a closer look at how an actual solution might look like. As a kind of kickoff for a discussion, I have drafted the following document which outlines how such a solution could look like.

Any comments are very appreciated!

Proposal: Architecture for session based login in Dashboards

Goals and basic requirements

  • Compact cookie size. Get rid of issues due to excessive cookie size.
  • "Logout" is capable of destroying the session
  • Usable with any authentication type available for Dashboards (i.e., password based auth, OIDC and SAML)
  • Sessions expire after a certain period of inactivity (i.e., an access to a session extends its time to live). However, there shall be also an absolute maximum time, after which a session gets invalidated.
  • Requires no external dependencies.
  • Should not facilitate DOS attacks by unauthenticated users.
  • Usable with OpenSearch Dashboards 2.x

Non-goals

  • Only meant for authentication at OpenSearch via Dashboards. Clients directly authenticating at OpenSearch won't be affected.
  • In order to keep the scope manageable, this does not yet take any plans for OpenSearch 3 into account.
  • The session feature is only meant for authentication. It shall not provide a flexible session storage or similar functionality.

Open: Goals or non-goals

For these items, it needs to be clarified whether it shall be a goal or not:

  • Shall the old session-less authentication mechanism remain available or shall it be replaced by the new mechanism
  • Related: Is it acceptable that users get logged out when switching to the new mechanism?
  • Shall the existing configuration be re-used or shall it change for session login?
  • Besides the default session storage, shall we provide also support for external storage components such as Redis?
  • What about exotic authentication mechanisms in Dashboards such as proxy auth?

Fundamental design

  • Introduce a new REST API which consumes credentials (user name, password or SAML AuthnResponses or OIDC tokens), validates these, creates a session and returns a session handle. This REST API is provided by the security plugin of the OpenSearch backend. The REST API is used by the Dashboards security plugin to create a session when a user is trying to log in.
  • The session handle is actually a signed JWT. In contrast to the current JWT usage of Dashboards, the JWT shall only contain a session ID. It shall not contain information about roles or user attributes. By using a signed JWT, we can avoid a certain class of DOS attacks of unauthenticated users on the session storage, as we can validate the JWT before hitting the session storage.
  • By default, sessions are stored in a private OpenSearch index. Each session is represented by one document. A session document contains: User name, roles, user attributes, session expiry time.
  • Dashboards saves the session JWT at the client side using a cookie.
  • The Dashboards security plugin reads that cookie, extracts the JWT and sends it along with every request it issues to the OpenSearch backend. It is sent inside a HTTP Authentication: bearer header.
  • The OpenSearch backend has a new authentication module that can check the validity of the JWT based on its signature and the private session store. If the JWT is invalid or the session is expired, the OpenSearch backend issues a 401 response.

Open design decisions

  • Dashboards can generate quite a lot requests during a single page load. Is it okay that every single request triggers an access to the internal session index? Or do we need a kind of cache in front of Open Search? We also need to take into account that using a session is supposed to extend the session lifetime. Thus, we actually would need to write information to the index when a session is used.

@davidlago
Copy link
Author

I've run some tests with actual SAML payloads with 200 SAML roles in them, and after compressing them they are still under 4Kb:

80 -rw-r--r--   1 davelago  38091 Feb 15 13:32 saml_response_200_roles.txt
 8 -rw-r--r--   1 davelago   3723 Feb 15 13:32 saml_response_200_roles.txt.gz

For reference, the js I used to test compression was:

const { createGzip } = require('node:zlib');
const { pipeline } = require('node:stream');
const {
  createReadStream,
  createWriteStream,
} = require('node:fs');

const gzip = createGzip();
const source = createReadStream('saml_response_200_roles.txt');
const destination = createWriteStream('saml_response_200_roles.txt.gz');

pipeline(source, gzip, destination, (err) => {
  if (err) {
    console.error('An error occurred:', err);
    process.exitCode = 1;
  }
});

It seems like a worthy fix to add compression to solve the immediate painpoint, and we can tackle the larger server-side session management as part of those ongoing efforts (opensearch-project/OpenSearch-Dashboards#1215, opensearch-project/OpenSearch-Dashboards#1441).

@jimishs
Copy link

jimishs commented Feb 15, 2023

+1 to the idea of cookie compression and optimizing cookie to exclude parameters that arent needed / can be removed.

Regarding the question of upper bound - im aware of customers with 800-1000 workgroup attributes (that may or may not map to one or more OpenSearch security roles). So while the size could vary, 20-30 kb was what was estimated for such large assertions. If we can go upto 44kb, uncompressed, that could solve near term concerns for large customers.

@nibix
Copy link

nibix commented Feb 16, 2023

Just a small clarification regarding SAML responses: The Dashboards security plugin never stores SAML responses in its cookies. Rather, it converts these into a JWT using an API in the OpenSearch backend.

Still, as these JWTs are not encrypted, these should also have a good compression ratio, but maybe not as big as for the XML based and very verbose SAML.

Just looking quickly at the OIDC case:

For OIDC, the id_token is stored in the cookie. The id_token can be compressed as well. However, some IdPs might choose to provide encrypted id_tokens. As encrypted data is not well compressible, this will not provide such a strong benefit (it will bring some benefit by compensating for the base64 encoding size gain).

@nibix
Copy link

nibix commented Feb 21, 2023

I have filed a draft pull request with a first shot at the compression solution. See #1338

Observations so far:

  • The core Dashboards/Hapi session cookie storage mechanism uses JSON to serialize the payload. In order to put compressed data - which is binary - into the JSON payload, we need to base64 encode it. This nullifies a part of the compression effect. We are still looking into serializing the cookie differently to avoid the base64 encoding.
  • In order to verify the actual effectiveness of this change, some real world example (or close to real world example) of a payload triggering the issue would be great.
  • First test with made up test data: JWT with 400 roles: 26 kb raw -> compression: 12 kb binary -> base64 encoding: 16kb -> encryption and additional base64 encoding: 20 kb

We are still looking into other ways to serialize and store the payload to avoid all these encoding losses.

@nibix
Copy link

nibix commented Feb 22, 2023

I have created a sample SAML AuthnResponse to serve as a test case for our research. The AuthnResponse contains 200 roles encoded in a DN format. I understand that even though this is quite a big amount, it is still something that is realistic and must be expected.

The encoded SAML AuthnResponse (28 kb):

PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+PHNhbWwycDpSZXNwb25zZSB4bWxuczpzYW1sMnA9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpwcm90b2NvbCIgSUQ9Ik1PQ0tTQU1MXzEiIEluUmVzcG9uc2VUbz0iT05FTE9HSU5fNzAzY2E3YzUtMmJlZi00ODc4LTk1ZjktZGE1MzNkNmI1ZjlkIiBJc3N1ZUluc3RhbnQ9IjIwMjMtMDItMjJUMDc6NDI6NTQuOTk1WiIgVmVyc2lvbj0iMi4wIj48c2FtbDJwOlN0YXR1cz48c2FtbDJwOlN0YXR1c0NvZGUgVmFsdWU9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpzdGF0dXM6U3VjY2VzcyIvPjwvc2FtbDJwOlN0YXR1cz48c2FtbDI6QXNzZXJ0aW9uIHhtbG5zOnNhbWwyPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBJRD0iTU9DS1NBTUxfMiIgSXNzdWVJbnN0YW50PSIyMDIzLTAyLTIyVDA3OjQyOjU0Ljk5NloiIFZlcnNpb249IjIuMCI+PHNhbWwyOklzc3Vlcj5odHRwOi8vdGVzdC5lbnRpdHk8L3NhbWwyOklzc3Vlcj48ZHM6U2lnbmF0dXJlIHhtbG5zOmRzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIj4KPGRzOlNpZ25lZEluZm8+CjxkczpDYW5vbmljYWxpemF0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+CjxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjcnNhLXNoYTEiLz4KPGRzOlJlZmVyZW5jZSBVUkk9IiNNT0NLU0FNTF8yIj4KPGRzOlRyYW5zZm9ybXM+CjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVyZSIvPgo8ZHM6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8xMC94bWwtZXhjLWMxNG4jIi8+CjwvZHM6VHJhbnNmb3Jtcz4KPGRzOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jI3NoYTI1NiIvPgo8ZHM6RGlnZXN0VmFsdWU+MkhzbHgyUGpBYXVnZ0tORFVWUWxncE9CTkNRSkhjdnlUT1Erdk0zbUxaND08L2RzOkRpZ2VzdFZhbHVlPgo8L2RzOlJlZmVyZW5jZT4KPC9kczpTaWduZWRJbmZvPgo8ZHM6U2lnbmF0dXJlVmFsdWU+Cm9aNHpRc3pUNzlJcm1qbVQ4eGdJdEQrb1FKQjhiN1BFRzl3NmR1UWJyMkM1YVI1aFpOVGdGZ1NLdjc2ZTNHNENDNk9QSVhtZG9TOTMmIzEzOwo3REx1bmhhMWhCRG03R0FEUWh6MktONEtkeEo2Q3FlbHJZZEZrbTlhYUYzcHVtQTczaUNVd043bTV1TVlkcXpWV204Qnp2V1Y5K253JiMxMzsKM3lnNUJyTW5GTTV0ZDltUWYzWmdNaGFCUFhzRnVheUV1RnhGeXpzL0RTWkVOUnh6Q1dkeUNMR1pCK0xvWlhrZzNhUnhiM0lpem1XdSYjMTM7CkdhV0oydWFHejFNR1JZVG05YWxlQWpoT1RhYmhPNS9zSVFuWG1aY21IWFVlVU1heTZjck53RHNYYkhkdkNpVnNiZ1JxZFF3cDF5ejAmIzEzOwo3b0RHWi9yMHFCeHBnZG55ODNDOXcxdk9vbTBXQ21OT1o2NnFRdz09CjwvZHM6U2lnbmF0dXJlVmFsdWU+CjwvZHM6U2lnbmF0dXJlPjxzYW1sMjpTdWJqZWN0PjxzYW1sMjpOYW1lSUQgRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjE6bmFtZWlkLWZvcm1hdDp1bnNwZWNpZmllZCI+aG9yc3Q8L3NhbWwyOk5hbWVJRD48c2FtbDI6U3ViamVjdENvbmZpcm1hdGlvbiBNZXRob2Q9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpjbTpiZWFyZXIiPjxzYW1sMjpTdWJqZWN0Q29uZmlybWF0aW9uRGF0YSBJblJlc3BvbnNlVG89Ik9ORUxPR0lOXzcwM2NhN2M1LTJiZWYtNDg3OC05NWY5LWRhNTMzZDZiNWY5ZCIgTm90T25PckFmdGVyPSIyMDIzLTAyLTIyVDA3OjQzOjU0Ljk5N1oiIFJlY2lwaWVudD0iaHR0cDovL3doZXJldmVyL3NhbWwvYWNzIi8+PC9zYW1sMjpTdWJqZWN0Q29uZmlybWF0aW9uPjwvc2FtbDI6U3ViamVjdD48c2FtbDI6Q29uZGl0aW9ucyBOb3RCZWZvcmU9IjIwMjMtMDItMjJUMDc6NDI6NTQuOTk4WiIgTm90T25PckFmdGVyPSIyMDIzLTAyLTIyVDA3OjQzOjU0Ljk5OFoiLz48c2FtbDI6QXV0aG5TdGF0ZW1lbnQgQXV0aG5JbnN0YW50PSIyMDIzLTAyLTIyVDA3OjQyOjU0Ljk5NloiIFNlc3Npb25JbmRleD0iTU9DS1NBTUxfMyI+PHNhbWwyOkF1dGhuQ29udGV4dD48c2FtbDI6QXV0aG5Db250ZXh0Q2xhc3NSZWY+dXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFjOmNsYXNzZXM6dW5zcGVjaWZpZWQ8L3NhbWwyOkF1dGhuQ29udGV4dENsYXNzUmVmPjwvc2FtbDI6QXV0aG5Db250ZXh0Pjwvc2FtbDI6QXV0aG5TdGF0ZW1lbnQ+PHNhbWwyOkF0dHJpYnV0ZVN0YXRlbWVudD48c2FtbDI6QXR0cmlidXRlIE5hbWU9InJvbGVzIiBOYW1lRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXR0cm5hbWUtZm9ybWF0OmJhc2ljIj48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249U3lzdGVtQWRtaW5zLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPU5ldHdvcmtFbmdpbmVlcnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249RGF0YWJhc2VBZG1pbnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249U2VjdXJpdHlBbmFseXN0cyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1BcHBsaWNhdGlvbkRldmVsb3BlcnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249SGVscERlc2ssb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249SHVtYW5SZXNvdXJjZXMsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249QWNjb3VudGluZyxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1NYXJrZXRpbmcsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249U2FsZXMsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249Q3VzdG9tZXJTZXJ2aWNlLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVdhcmVob3VzZSxvdT1PcGVyYXRpb25zRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVNoaXBwaW5nLG91PU9wZXJhdGlvbnNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249UHJvZHVjdGlvbixvdT1PcGVyYXRpb25zRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVJlc2VhcmNoLG91PURldmVsb3BtZW50RGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPURldmVsb3BtZW50LG91PURldmVsb3BtZW50RGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVRlc3Rpbmcsb3U9RGV2ZWxvcG1lbnREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249UXVhbGl0eUNvbnRyb2wsb3U9T3BlcmF0aW9uc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1MZWdhbCxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1GYWNpbGl0aWVzLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUV4ZWN1dGl2ZSxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1DdXN0b21lclJlbGF0aW9ucyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1Qcm9jdXJlbWVudCxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1QdWJsaWNSZWxhdGlvbnMsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249RmluYW5jZSxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1BY2NvdW50c1BheWFibGUsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249QWNjb3VudHNSZWNlaXZhYmxlLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVBheXJvbGwsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249QmVuZWZpdHMsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249VHJhaW5pbmcsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249SGVscGRlc2tMZXZlbDEsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249SGVscGRlc2tMZXZlbDIsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249SGVscGRlc2tMZXZlbDMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249QmFja3VwT3BlcmF0b3JzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUNsb3VkRW5naW5lZXJzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPURhdGFiYXNlT3BlcmF0b3JzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPURhdGFiYXNlRGV2ZWxvcGVycyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1XZWJEZXZlbG9wZXJzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPU1vYmlsZURldmVsb3BlcnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249U29mdHdhcmVEZXZlbG9wZXJzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVVJVVhEZXNpZ25lcnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249UHJvamVjdE1hbmFnZXJzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPU5ldHdvcmtBZG1pbnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249U2VydmVyQWRtaW5zLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUZpcmV3YWxsQWRtaW5zLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUFudGl2aXJ1c0FkbWlucyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1TeXN0ZW1FbmdpbmVlcnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249QXBwbGljYXRpb25TdXBwb3J0LG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVRlY2huaWNhbFN1cHBvcnQsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249T3BlcmF0aW9ucyxvdT1PcGVyYXRpb25zRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUxvZ2lzdGljcyxvdT1PcGVyYXRpb25zRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUN1c3RvbWVyU3VwcG9ydCxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1NYXJrZXRSZXNlYXJjaCxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1Qcm9kdWN0TWFuYWdlbWVudCxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1TYWxlc01hbmFnZXJzLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUN1c3RvbWVyU3VjY2VzcyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1DdXN0b21lckV4cGVyaWVuY2Usb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249UHJvZHVjdERldmVsb3BtZW50LG91PURldmVsb3BtZW50RGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVByb2R1Y3REZXNpZ24sb3U9RGV2ZWxvcG1lbnREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249UHJvZHVjdFRlc3Rpbmcsb3U9RGV2ZWxvcG1lbnREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249UHJvZHVjdFF1YWxpdHksb3U9RGV2ZWxvcG1lbnREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249VGVjaG5pY2FsV3JpdGVycyxvdT1EZXZlbG9wbWVudERlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1SZXNlYXJjaE1hbmFnZXJzLG91PURldmVsb3BtZW50RGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVJlc2VhcmNoQW5hbHlzdHMsb3U9RGV2ZWxvcG1lbnREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249Q2hpZWZUZWNobm9sb2d5T2ZmaWNlcixvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1DaGllZk9wZXJhdGluZ09mZmljZXIsb3U9T3BlcmF0aW9uc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1DaGllZlNhbGVzT2ZmaWNlcixvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1DaGllZk1hcmtldGluZ09mZmljZXIsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249Q2hpZWZGaW5hbmNpYWxPZmZpY2VyLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUNoaWVmSHVtYW5SZXNvdXJjZXNPZmZpY2VyLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUNoaWVmRXhlY3V0aXZlT2ZmaWNlcixvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1TYWxlc1N1cHBvcnQsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249U2FsZXNFbmdpbmVlcnMsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249U2FsZXNPcGVyYXRpb25zLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVNhbGVzQWRtaW5pc3RyYXRpb24sb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249U2FsZXNBbmFseXN0cyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1NYXJrZXRpbmdPcGVyYXRpb25zLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPU1hcmtldGluZ0FkbWluaXN0cmF0aW9uLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPU1hcmtldGluZ0FuYWx5c3RzLG91PVNhbGVzRGVwdCxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1TeXN0ZW1BZG1pbnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249TmV0d29ya0VuZ2luZWVycyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1EYXRhYmFzZUFkbWlucyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1TZWN1cml0eUFuYWx5c3RzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUFwcGxpY2F0aW9uRGV2ZWxvcGVycyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1IZWxwRGVzayxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1IdW1hblJlc291cmNlcyxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1BY2NvdW50aW5nLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPU1hcmtldGluZyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1TYWxlcyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1DdXN0b21lclNlcnZpY2Usb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249V2FyZWhvdXNlLG91PU9wZXJhdGlvbnNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249U2hpcHBpbmcsb3U9T3BlcmF0aW9uc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1Qcm9kdWN0aW9uLG91PU9wZXJhdGlvbnNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249UmVzZWFyY2gsb3U9RGV2ZWxvcG1lbnREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249RGV2ZWxvcG1lbnQsb3U9RGV2ZWxvcG1lbnREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249VGVzdGluZyxvdT1EZXZlbG9wbWVudERlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1RdWFsaXR5Q29udHJvbCxvdT1PcGVyYXRpb25zRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUxlZ2FsLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUZhY2lsaXRpZXMsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249RXhlY3V0aXZlLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUN1c3RvbWVyUmVsYXRpb25zLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVByb2N1cmVtZW50LG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVB1YmxpY1JlbGF0aW9ucyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1GaW5hbmNlLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUFjY291bnRzUGF5YWJsZSxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1BY2NvdW50c1JlY2VpdmFibGUsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249UGF5cm9sbCxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1CZW5lZml0cyxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1UcmFpbmluZyxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1IZWxwZGVza0xldmVsMSxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1IZWxwZGVza0xldmVsMixvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1IZWxwZGVza0xldmVsMyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1CYWNrdXBPcGVyYXRvcnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249Q2xvdWRFbmdpbmVlcnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249RGF0YWJhc2VPcGVyYXRvcnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249RGF0YWJhc2VEZXZlbG9wZXJzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVdlYkRldmVsb3BlcnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249TW9iaWxlRGV2ZWxvcGVycyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1Tb2Z0d2FyZURldmVsb3BlcnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249VUkvVVhEZXNpZ25lcnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249UHJvamVjdE1hbmFnZXJzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPU5ldHdvcmtBZG1pbnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249U2VydmVyQWRtaW5zLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUZpcmV3YWxsQWRtaW5zLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUFudGl2aXJ1c0FkbWlucyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1TeXN0ZW1FbmdpbmVlcnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249QXBwbGljYXRpb25TdXBwb3J0LG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVRlY2huaWNhbFN1cHBvcnQsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249T3BlcmF0aW9ucyxvdT1PcGVyYXRpb25zRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUxvZ2lzdGljcyxvdT1PcGVyYXRpb25zRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUN1c3RvbWVyU3VwcG9ydCxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1NYXJrZXRSZXNlYXJjaCxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1Qcm9kdWN0TWFuYWdlbWVudCxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1TYWxlc01hbmFnZXJzLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUN1c3RvbWVyU3VjY2VzcyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1DdXN0b21lckV4cGVyaWVuY2Usb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249UHJvZHVjdERldmVsb3BtZW50LG91PURldmVsb3BtZW50RGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVByb2R1Y3REZXNpZ24sb3U9RGV2ZWxvcG1lbnREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249UHJvZHVjdFRlc3Rpbmcsb3U9RGV2ZWxvcG1lbnREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249UHJvZHVjdFF1YWxpdHksb3U9RGV2ZWxvcG1lbnREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249VGVjaG5pY2FsV3JpdGVycyxvdT1EZXZlbG9wbWVudERlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1SZXNlYXJjaE1hbmFnZXJzLG91PURldmVsb3BtZW50RGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVJlc2VhcmNoQW5hbHlzdHMsb3U9RGV2ZWxvcG1lbnREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249Q2hpZWZUZWNobm9sb2d5T2ZmaWNlcixvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1DaGllZk9wZXJhdGluZ09mZmljZXIsb3U9T3BlcmF0aW9uc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1DaGllZlNhbGVzT2ZmaWNlcixvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1DaGllZk1hcmtldGluZ09mZmljZXIsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249Q2hpZWZGaW5hbmNpYWxPZmZpY2VyLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUNoaWVmSHVtYW5SZXNvdXJjZXNPZmZpY2VyLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUNoaWVmRXhlY3V0aXZlT2ZmaWNlcixvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1TYWxlc1N1cHBvcnQsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249U2FsZXNFbmdpbmVlcnMsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249U2FsZXNPcGVyYXRpb25zLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVNhbGVzQWRtaW5pc3RyYXRpb24sb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249U2FsZXNBbmFseXN0cyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1NYXJrZXRpbmdPcGVyYXRpb25zLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPU1hcmtldGluZ0FkbWluaXN0cmF0aW9uLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPU1hcmtldGluZ0FuYWx5c3RzLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUN1c3RvbWVyUmVsYXRpb25zLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUN1c3RvbWVyUmV0ZW50aW9uLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVByb2R1Y3RNYXJrZXRpbmcsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249Q2hhbm5lbE1hcmtldGluZyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1EaWdpdGFsTWFya2V0aW5nLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUNvbnRlbnRNYXJrZXRpbmcsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249TWFya2V0QW5hbHlzaXMsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249QnJhbmRNYW5hZ2VtZW50LG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUZpbmFuY2lhbFJlcG9ydGluZyxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1GaW5hbmNpYWxQbGFubmluZyxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1BY2NvdW50c1JlY2VpdmFibGUsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249QWNjb3VudHNQYXlhYmxlLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVBheXJvbGxBZG1pbmlzdHJhdGlvbixvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1UYXhhdGlvbixvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1BdWRpdCxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1MZWdhbENvbXBsaWFuY2Usb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249SHVtYW5SZXNvdXJjZXNPcGVyYXRpb25zLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUh1bWFuUmVzb3VyY2VzQWRtaW5pc3RyYXRpb24sb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249VGFsZW50TWFuYWdlbWVudCxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1SZWNydWl0bWVudCxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1FbXBsb3llZVJlbGF0aW9ucyxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1FbXBsb3llZVdlbGxuZXNzLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUZhY2lsaXRpZXNNYW5hZ2VtZW50LG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPU9mZmljZUFkbWluaXN0cmF0aW9uLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVRyYXZlbE1hbmFnZW1lbnQsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249UHJvY3VyZW1lbnQsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249U3VwcGx5Q2hhaW5NYW5hZ2VtZW50LG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPVdhcmVob3VzZU1hbmFnZW1lbnQsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249UHJvZHVjdGlvblBsYW5uaW5nLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPU1hbnVmYWN0dXJpbmcsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249UXVhbGl0eUFzc3VyYW5jZSxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1RdWFsaXR5Q29udHJvbCxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1IZWFsdGhBbmRTYWZldHksb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249RW52aXJvbm1lbnRhbE1hbmFnZW1lbnQsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249UmVzZWFyY2hBbmREZXZlbG9wbWVudCxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1JbnRlbGxlY3R1YWxQcm9wZXJ0eSxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1Db3Jwb3JhdGVTb2NpYWxSZXNwb25zaWJpbGl0eSxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjxzYW1sMjpBdHRyaWJ1dGVWYWx1ZT5jbj1Db21tdW5pdHlSZWxhdGlvbnMsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249SW52ZXN0b3JSZWxhdGlvbnMsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249SW50ZXJuYWxBdWRpdG9yLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+PHNhbWwyOkF0dHJpYnV0ZVZhbHVlPmNuPUluZm9ybWF0aW9uVGVjaG5vbG9neU9wZXJhdGlvbnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT48c2FtbDI6QXR0cmlidXRlVmFsdWU+Y249QXBwbGljYXRpb25EZXZlbG9wbWVudCxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb208L3NhbWwyOkF0dHJpYnV0ZVZhbHVlPjwvc2FtbDI6QXR0cmlidXRlPjwvc2FtbDI6QXR0cmlidXRlU3RhdGVtZW50Pjwvc2FtbDI6QXNzZXJ0aW9uPjwvc2FtbDJwOlJlc3BvbnNlPg==

The JWT created by the security plugin from the AuthnResponse (14kb):

eyJhbGciOiJIUzUxMiJ9.eyJuYmYiOjE2NzcwNTE3NzUsImV4cCI6MTY3NzA1NTM3NSwic3ViIjoiaG9yc3QiLCJzYW1sX25pZiI6InUiLCJzYW1sX3NpIjoiTU9DS1NBTUxfMyIsInJvbGVzIjpbImNuPVN5c3RlbUFkbWlucyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1OZXR3b3JrRW5naW5lZXJzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPURhdGFiYXNlQWRtaW5zLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVNlY3VyaXR5QW5hbHlzdHMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249QXBwbGljYXRpb25EZXZlbG9wZXJzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUhlbHBEZXNrLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUh1bWFuUmVzb3VyY2VzLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUFjY291bnRpbmcsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249TWFya2V0aW5nLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVNhbGVzLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUN1c3RvbWVyU2VydmljZSxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1XYXJlaG91c2Usb3U9T3BlcmF0aW9uc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1TaGlwcGluZyxvdT1PcGVyYXRpb25zRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVByb2R1Y3Rpb24sb3U9T3BlcmF0aW9uc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1SZXNlYXJjaCxvdT1EZXZlbG9wbWVudERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1EZXZlbG9wbWVudCxvdT1EZXZlbG9wbWVudERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1UZXN0aW5nLG91PURldmVsb3BtZW50RGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVF1YWxpdHlDb250cm9sLG91PU9wZXJhdGlvbnNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249TGVnYWwsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249RmFjaWxpdGllcyxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1FeGVjdXRpdmUsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249Q3VzdG9tZXJSZWxhdGlvbnMsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249UHJvY3VyZW1lbnQsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249UHVibGljUmVsYXRpb25zLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUZpbmFuY2Usb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249QWNjb3VudHNQYXlhYmxlLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUFjY291bnRzUmVjZWl2YWJsZSxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1QYXlyb2xsLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUJlbmVmaXRzLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVRyYWluaW5nLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUhlbHBkZXNrTGV2ZWwxLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUhlbHBkZXNrTGV2ZWwyLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUhlbHBkZXNrTGV2ZWwzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUJhY2t1cE9wZXJhdG9ycyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1DbG91ZEVuZ2luZWVycyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1EYXRhYmFzZU9wZXJhdG9ycyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1EYXRhYmFzZURldmVsb3BlcnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249V2ViRGV2ZWxvcGVycyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1Nb2JpbGVEZXZlbG9wZXJzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVNvZnR3YXJlRGV2ZWxvcGVycyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1VSVVYRGVzaWduZXJzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVByb2plY3RNYW5hZ2VycyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1OZXR3b3JrQWRtaW5zLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVNlcnZlckFkbWlucyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1GaXJld2FsbEFkbWlucyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1BbnRpdmlydXNBZG1pbnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249U3lzdGVtRW5naW5lZXJzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUFwcGxpY2F0aW9uU3VwcG9ydCxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1UZWNobmljYWxTdXBwb3J0LG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPU9wZXJhdGlvbnMsb3U9T3BlcmF0aW9uc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1Mb2dpc3RpY3Msb3U9T3BlcmF0aW9uc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1DdXN0b21lclN1cHBvcnQsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249TWFya2V0UmVzZWFyY2gsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249UHJvZHVjdE1hbmFnZW1lbnQsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249U2FsZXNNYW5hZ2VycyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1DdXN0b21lclN1Y2Nlc3Msb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249Q3VzdG9tZXJFeHBlcmllbmNlLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVByb2R1Y3REZXZlbG9wbWVudCxvdT1EZXZlbG9wbWVudERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1Qcm9kdWN0RGVzaWduLG91PURldmVsb3BtZW50RGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVByb2R1Y3RUZXN0aW5nLG91PURldmVsb3BtZW50RGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVByb2R1Y3RRdWFsaXR5LG91PURldmVsb3BtZW50RGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVRlY2huaWNhbFdyaXRlcnMsb3U9RGV2ZWxvcG1lbnREZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249UmVzZWFyY2hNYW5hZ2VycyxvdT1EZXZlbG9wbWVudERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1SZXNlYXJjaEFuYWx5c3RzLG91PURldmVsb3BtZW50RGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUNoaWVmVGVjaG5vbG9neU9mZmljZXIsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249Q2hpZWZPcGVyYXRpbmdPZmZpY2VyLG91PU9wZXJhdGlvbnNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249Q2hpZWZTYWxlc09mZmljZXIsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249Q2hpZWZNYXJrZXRpbmdPZmZpY2VyLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUNoaWVmRmluYW5jaWFsT2ZmaWNlcixvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1DaGllZkh1bWFuUmVzb3VyY2VzT2ZmaWNlcixvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1DaGllZkV4ZWN1dGl2ZU9mZmljZXIsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249U2FsZXNTdXBwb3J0LG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVNhbGVzRW5naW5lZXJzLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVNhbGVzT3BlcmF0aW9ucyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1TYWxlc0FkbWluaXN0cmF0aW9uLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVNhbGVzQW5hbHlzdHMsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249TWFya2V0aW5nT3BlcmF0aW9ucyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1NYXJrZXRpbmdBZG1pbmlzdHJhdGlvbixvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1NYXJrZXRpbmdBbmFseXN0cyxvdT1TYWxlc0RlcHQsZGM9Y29tIiwiY249U3lzdGVtQWRtaW5zLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPU5ldHdvcmtFbmdpbmVlcnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249RGF0YWJhc2VBZG1pbnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249U2VjdXJpdHlBbmFseXN0cyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1BcHBsaWNhdGlvbkRldmVsb3BlcnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249SGVscERlc2ssb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249SHVtYW5SZXNvdXJjZXMsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249QWNjb3VudGluZyxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1NYXJrZXRpbmcsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249U2FsZXMsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249Q3VzdG9tZXJTZXJ2aWNlLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVdhcmVob3VzZSxvdT1PcGVyYXRpb25zRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVNoaXBwaW5nLG91PU9wZXJhdGlvbnNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249UHJvZHVjdGlvbixvdT1PcGVyYXRpb25zRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVJlc2VhcmNoLG91PURldmVsb3BtZW50RGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPURldmVsb3BtZW50LG91PURldmVsb3BtZW50RGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVRlc3Rpbmcsb3U9RGV2ZWxvcG1lbnREZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249UXVhbGl0eUNvbnRyb2wsb3U9T3BlcmF0aW9uc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1MZWdhbCxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1GYWNpbGl0aWVzLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUV4ZWN1dGl2ZSxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1DdXN0b21lclJlbGF0aW9ucyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1Qcm9jdXJlbWVudCxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1QdWJsaWNSZWxhdGlvbnMsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249RmluYW5jZSxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1BY2NvdW50c1BheWFibGUsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249QWNjb3VudHNSZWNlaXZhYmxlLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVBheXJvbGwsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249QmVuZWZpdHMsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249VHJhaW5pbmcsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249SGVscGRlc2tMZXZlbDEsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249SGVscGRlc2tMZXZlbDIsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249SGVscGRlc2tMZXZlbDMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249QmFja3VwT3BlcmF0b3JzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUNsb3VkRW5naW5lZXJzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPURhdGFiYXNlT3BlcmF0b3JzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPURhdGFiYXNlRGV2ZWxvcGVycyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1XZWJEZXZlbG9wZXJzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPU1vYmlsZURldmVsb3BlcnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249U29mdHdhcmVEZXZlbG9wZXJzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVVJL1VYRGVzaWduZXJzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVByb2plY3RNYW5hZ2VycyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1OZXR3b3JrQWRtaW5zLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVNlcnZlckFkbWlucyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1GaXJld2FsbEFkbWlucyxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1BbnRpdmlydXNBZG1pbnMsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249U3lzdGVtRW5naW5lZXJzLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUFwcGxpY2F0aW9uU3VwcG9ydCxvdT1JVERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1UZWNobmljYWxTdXBwb3J0LG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPU9wZXJhdGlvbnMsb3U9T3BlcmF0aW9uc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1Mb2dpc3RpY3Msb3U9T3BlcmF0aW9uc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1DdXN0b21lclN1cHBvcnQsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249TWFya2V0UmVzZWFyY2gsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249UHJvZHVjdE1hbmFnZW1lbnQsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249U2FsZXNNYW5hZ2VycyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1DdXN0b21lclN1Y2Nlc3Msb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249Q3VzdG9tZXJFeHBlcmllbmNlLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVByb2R1Y3REZXZlbG9wbWVudCxvdT1EZXZlbG9wbWVudERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1Qcm9kdWN0RGVzaWduLG91PURldmVsb3BtZW50RGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVByb2R1Y3RUZXN0aW5nLG91PURldmVsb3BtZW50RGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVByb2R1Y3RRdWFsaXR5LG91PURldmVsb3BtZW50RGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVRlY2huaWNhbFdyaXRlcnMsb3U9RGV2ZWxvcG1lbnREZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249UmVzZWFyY2hNYW5hZ2VycyxvdT1EZXZlbG9wbWVudERlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1SZXNlYXJjaEFuYWx5c3RzLG91PURldmVsb3BtZW50RGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUNoaWVmVGVjaG5vbG9neU9mZmljZXIsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249Q2hpZWZPcGVyYXRpbmdPZmZpY2VyLG91PU9wZXJhdGlvbnNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249Q2hpZWZTYWxlc09mZmljZXIsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249Q2hpZWZNYXJrZXRpbmdPZmZpY2VyLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUNoaWVmRmluYW5jaWFsT2ZmaWNlcixvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1DaGllZkh1bWFuUmVzb3VyY2VzT2ZmaWNlcixvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1DaGllZkV4ZWN1dGl2ZU9mZmljZXIsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249U2FsZXNTdXBwb3J0LG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVNhbGVzRW5naW5lZXJzLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVNhbGVzT3BlcmF0aW9ucyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1TYWxlc0FkbWluaXN0cmF0aW9uLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVNhbGVzQW5hbHlzdHMsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249TWFya2V0aW5nT3BlcmF0aW9ucyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1NYXJrZXRpbmdBZG1pbmlzdHJhdGlvbixvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1NYXJrZXRpbmdBbmFseXN0cyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1DdXN0b21lclJlbGF0aW9ucyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1DdXN0b21lclJldGVudGlvbixvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1Qcm9kdWN0TWFya2V0aW5nLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUNoYW5uZWxNYXJrZXRpbmcsb3U9U2FsZXNEZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249RGlnaXRhbE1hcmtldGluZyxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1Db250ZW50TWFya2V0aW5nLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPU1hcmtldEFuYWx5c2lzLG91PVNhbGVzRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUJyYW5kTWFuYWdlbWVudCxvdT1TYWxlc0RlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1GaW5hbmNpYWxSZXBvcnRpbmcsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249RmluYW5jaWFsUGxhbm5pbmcsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249QWNjb3VudHNSZWNlaXZhYmxlLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUFjY291bnRzUGF5YWJsZSxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1QYXlyb2xsQWRtaW5pc3RyYXRpb24sb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249VGF4YXRpb24sb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249QXVkaXQsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249TGVnYWxDb21wbGlhbmNlLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUh1bWFuUmVzb3VyY2VzT3BlcmF0aW9ucyxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1IdW1hblJlc291cmNlc0FkbWluaXN0cmF0aW9uLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVRhbGVudE1hbmFnZW1lbnQsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249UmVjcnVpdG1lbnQsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249RW1wbG95ZWVSZWxhdGlvbnMsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249RW1wbG95ZWVXZWxsbmVzcyxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1GYWNpbGl0aWVzTWFuYWdlbWVudCxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1PZmZpY2VBZG1pbmlzdHJhdGlvbixvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1UcmF2ZWxNYW5hZ2VtZW50LG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVByb2N1cmVtZW50LG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVN1cHBseUNoYWluTWFuYWdlbWVudCxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1XYXJlaG91c2VNYW5hZ2VtZW50LG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVByb2R1Y3Rpb25QbGFubmluZyxvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1NYW51ZmFjdHVyaW5nLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVF1YWxpdHlBc3N1cmFuY2Usb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249UXVhbGl0eUNvbnRyb2wsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249SGVhbHRoQW5kU2FmZXR5LG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUVudmlyb25tZW50YWxNYW5hZ2VtZW50LG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPVJlc2VhcmNoQW5kRGV2ZWxvcG1lbnQsb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249SW50ZWxsZWN0dWFsUHJvcGVydHksb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249Q29ycG9yYXRlU29jaWFsUmVzcG9uc2liaWxpdHksb3U9QWRtaW5EZXB0LGRjPWNvbXBhbnksZGM9Y29tIiwiY249Q29tbXVuaXR5UmVsYXRpb25zLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUludmVzdG9yUmVsYXRpb25zLG91PUFkbWluRGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUludGVybmFsQXVkaXRvcixvdT1BZG1pbkRlcHQsZGM9Y29tcGFueSxkYz1jb20iLCJjbj1JbmZvcm1hdGlvblRlY2hub2xvZ3lPcGVyYXRpb25zLG91PUlURGVwdCxkYz1jb21wYW55LGRjPWNvbSIsImNuPUFwcGxpY2F0aW9uRGV2ZWxvcG1lbnQsb3U9SVREZXB0LGRjPWNvbXBhbnksZGM9Y29tIl19.oM0VAgxeElWHtohYbOt4VnisE3Ne87ZRdXKvngQPytpP7jHAFDQIK6akRzyXOcYy0_3IHbpwdFCieNei64m9wQ

When using the compression solution in #1338 this JWT goes through the following stages:

  • Deflate to binary data: 2326 byte
  • Base 64 encoded data (because we need to store in in JSON): 3104 byte
  • Embedded in JSON and iron encrypted and base 64 encoded (in order to store binary encrypted data as cookie): 4409 byte

Maximum cross-browser safe cookie size is 4093 bytes. Thus, the solution in #1338 won't work with the reference AuthnResponse.

Still, this size is blown up due to the double base64 encoding. We are still investigating ways to avoid the double encoding.

@prabhat-chaturvedi
Copy link

I guess in my previous post there was a confusion on Long term solution on Server based session management Vs Local Browser Session storage(another short term solution).
Not in complete favour of cookie compression apart from other issues stated above, cookie goes in each request thereby increasing the payload overhead.

Can we look into immediate short term solution alternative - using Local Session storage, as Cookie has limitations of 4MB, but Session Storage can go upto 10MB or more in some browsers.

The effort required are still the same, the place of compression and decompression - we need to put logic to put in browser session storage and pull out at the same entry and exit points.
Please don't confuse with Long term solution of server side session management, this proposal is for short term Browser session storage. This is the best practice as per the industry standard for session management and not storing details in the cookie as much as possible.

@nibix
Copy link

nibix commented Feb 22, 2023

@prabhat-chaturvedi

Not in complete favour of cookie compression apart from other issues stated above, cookie goes in each request thereby increasing the payload overhead.

As the possibly bloated JWT is the authentication token, we must pass it to Dashboards (and the OpenSearch backend) for every request. Otherwise, these requests are unauthenticated.

@prabhat-chaturvedi
Copy link

True, @nibix - all that remains as is, instead of storing the JWT in the cookie, store in something like session.setAttribute("autheticatedJWT", actualJWT).

  1. Only storage changes as a short term solution
  2. logic to send to backend remains same.
  3. code changes only around the place where we currently read and write cookie.

@expani
Copy link
Contributor

expani commented Feb 22, 2023

@prabhat-chaturvedi If we use local storage or any other means of storing the data instead of Cookie on browser side, then we need to read it and attach in every request sent from Dashboards front-end to Dashboards backend.

Currently, browser takes care of attaching the cookie with every request for us.

@prabhat-chaturvedi
Copy link

@anijain-Amazon I will have to dig deep onto it and limited to my knowledge specific to OpenSearch.
Generally assuming, there are two security context(sessions) which are talking about here.

Session 1 : User session at Dashboard frontend - where I propose to use browser session storage and passed on to below
Session 2 : Take info from above and Dashboard (acting as browser) to Security plugin - populate and send as a Authorization "Bearer" Header(as the best practices to send Bearer JWT for OAuth/OIDC) or other custom header.

@peternied
Copy link
Member

@nibix Great details with the reference cookie, 4409 byte is on the order of 4093 bytes.

If we employed a cookie splitter, seems like the base case without implementing the server side solution. Do you think that is a viable approach for the near term?

(Even setting aside the double base64 encoding issue - which means there might be even more headroom!)

@nibix
Copy link

nibix commented Feb 22, 2023

@peternied

If we employed a cookie splitter, seems like the base case without implementing the server side solution. Do you think that is a viable approach for the near term?

I believe that cookie splitting/stitching would be viable - but also tricky. The base solution linked in the PR above has the advantage that it is limited to the Dashboards security plugin. For more intrusive solutions, it is likely that we need to make changes in core Dashboards.

@expani
Copy link
Contributor

expani commented Feb 22, 2023

Session 1 : User session at Dashboard frontend - where I propose to use browser session storage and passed on to below

@prabhat-chaturvedi If we use Browser Session storage, then passing the credentials to every request to backend will require code changes at lots of places.

@jochen-kressin
Copy link
Contributor

jochen-kressin commented Feb 28, 2023

We have added a second PR to investigate the viability of splitting up a large payload into multiple cookies. See #1352

For this PR the focus was on doing this without any modifications to core Dashboards. This approach comes with some drawbacks though. There are some more details in the PR, but in short, creating a cookie from a plugin is a bit harder because of the abstraction layer on top of Hapi and the PR breaks this abstraction in a somewhat hacky way:

  • Registering cookies with the server by using the internal SessionStorage object's reference to the Hapi server
  • Writing the cookies via the raw Hapi requests cookie decorator (cookieAuth.set())

This could be improved a little by using a separate instance of Hapi Statehood, which manages the cookies for Hapi under the hood, but even with this I haven't (yet) been able to find a better way to write the cookie values.

Anyhow, I hope this PR at least serves as a basis for further discussions.

@jochen-kressin
Copy link
Contributor

A short status update on this:
We're working on cleaning up the PoC we started in #1352.

We've implemented this for OIDC as well, and we've made the number of additional cookies configurable.

One interesting finding that probably should be mentioned in the docs when this goes live is that if the id token from the IdP is very large, we may run into the following error:

server    log   [13:38:20.110] [error][plugins][securityDashboards] OpenId authentication failed: Error: [too_long_http_header_exception] HTTP header is larger than 8192 bytes. server    log   [13:38:23.333] [error][plugins][securityDashboards] OpenId authentication failed: Error: Request Timeout after 30000ms

I ran into this while testing an id token containing 200 roles. After receiving the token from the IdP, the authinfo endpoint is called with the token in the authorization header.
Luckily, this can be mitigated by changing the following value in opensearch.yml:
http.max_header_size: 16kb

I believe this is something that the customers would need to configure together with the cookie compression/splitting, otherwise the request will fail before we squeeze the token into the additional cookies.

Not sure if changing this setting has any negative side effects...?

@jochen-kressin
Copy link
Contributor

We've updated the pull request with the cookie stitching: #1352

The main difference is that it is now implemented for both OpenId and SAML.
I updated the description in the PR to reflect the changes, and I also added some questions to which I would appreciate your feedback.

The main questions going forward whether you would like the number of cookies to be configurable. There are some drawbacks to that, mainly related to if the customer changes the number of cookies.

We could also give making the number of used cookies dynamic another try. In other words don't register any cookies with the Hapi server, and instead try to write as many cookies as needed by the actual content.
The issue we ran into with that was that we weren't able to delete the cookies completely, e.g. when logging out...

Anyhow, happy for suggestions for improvements!

@expani
Copy link
Contributor

expani commented Apr 1, 2023

We can consider keeping this implementation as optional via configuration since most of the users of OpenSearch might not have a requirement of cookies more than 4Kb.

Also, we might be introducing some overhead in latency by extra base64 encoding, so turning this off if required can be desirable.

@nibix
Copy link

nibix commented Apr 2, 2023

@anijain-Amazon

Also, we might be introducing some overhead in latency by extra base64 encoding, so turning this off if required can be desirable.

This base64 encoding also occurs now and is kind of essential as the encrypted data is likely binary and cannot be stored as such in a cookie. Also, I don't believe that such a overhead is significant here.

@expani
Copy link
Contributor

expani commented Apr 3, 2023

@nibix I believe there was an additional layer of encoding added for spilt cookie approach. Agree that the latency might not be very high but the functionality of cookie splitting can be behind a configuration flag and disabled by default.

@nibix
Copy link

nibix commented Apr 3, 2023

The only additional encoding step is the compression.

@davidlago
Copy link
Author

We can consider keeping this implementation as optional via configuration since most of the users of OpenSearch might not have a requirement of cookies more than 4Kb.

Also, we might be introducing some overhead in latency by extra base64 encoding, so turning this off if required can be desirable.

Given that the ones turning this off would be users with small cookies to pass around, the overhead in their case would be quite negligible, and IMHO not worth the additional settings and code paths (that would also need to be tested) to make this an optional feature.

@nobletrout
Copy link

I am one of the many sufferers of getting booted out of dashboards after an hour. I have tried making the two recommended changes of extending the JWT time and cookie session length, but neither appears to make any meaningful change. Is there anything I can do as an admin/user today to increase this timeout value before getting kicked out to my IDP and having to re-auth. Other SAML based applications don't seem to suffer from this issue.

@expani
Copy link
Contributor

expani commented Apr 5, 2023

@nobletrout
For SAML Authentication, the expiry of the cookie is determined using the expiry of the JWT Token ( generated by Security Plugin by parsing the SAML Response ) CodePointer

The expiry of the JWT Token is determined using the SAML Response. CodePointer

Maybe you can try increasing the Session TTL at your IdP.

PS at the first glance, your issue seems to be not related to this RFC. Please feel free to open a separate Github issue for the same, so that the discussion can be continued there.

@davidlago
Copy link
Author

I believe #828 is the one you might be thinking of @anijain-Amazon... this issue links it at the top as one of the many things we'd like to fix with better session management. The cookie splitting work addresses just a few of these and more as a workaround for now, but yeah, there are still plenty of the ones linked above that won't be fixed this upcoming release.

@davidlago
Copy link
Author

Closing this RFC after #1352 got released in 2.7.0. If we decide to further improve session management (for example, adding server-side session management) we can track that as a separate issue/feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request triaged
Projects
None yet
Development

No branches or pull requests