flask_session_azure_c 0.4.6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flask_session_azure_c-0.4.6/LICENSE +21 -0
- flask_session_azure_c-0.4.6/PKG-INFO +88 -0
- flask_session_azure_c-0.4.6/README.md +56 -0
- flask_session_azure_c-0.4.6/flask_session_azure/__init__.py +15 -0
- flask_session_azure_c-0.4.6/flask_session_azure/storage_account.py +95 -0
- flask_session_azure_c-0.4.6/flask_session_azure/storage_account_session.py +102 -0
- flask_session_azure_c-0.4.6/flask_session_azure_c.egg-info/PKG-INFO +88 -0
- flask_session_azure_c-0.4.6/flask_session_azure_c.egg-info/SOURCES.txt +11 -0
- flask_session_azure_c-0.4.6/flask_session_azure_c.egg-info/dependency_links.txt +1 -0
- flask_session_azure_c-0.4.6/flask_session_azure_c.egg-info/requires.txt +3 -0
- flask_session_azure_c-0.4.6/flask_session_azure_c.egg-info/top_level.txt +1 -0
- flask_session_azure_c-0.4.6/setup.cfg +4 -0
- flask_session_azure_c-0.4.6/setup.py +32 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2020 Claas Diederichs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flask_session_azure_c
|
|
3
|
+
Version: 0.4.6
|
|
4
|
+
Summary: Flask Session using Azure Table Storage or CosmosDB table API
|
|
5
|
+
Home-page: https://github.com/bassmandan/FlaskAzureTableSession
|
|
6
|
+
Author: Claas Diederichs, Daniel Harding
|
|
7
|
+
Author-email:
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Framework :: Flask
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Requires-Python: >=3.6
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: azure-data-tables
|
|
20
|
+
Requires-Dist: pycryptodomex>=3.9.7
|
|
21
|
+
Requires-Dist: flask
|
|
22
|
+
Dynamic: author
|
|
23
|
+
Dynamic: classifier
|
|
24
|
+
Dynamic: description
|
|
25
|
+
Dynamic: description-content-type
|
|
26
|
+
Dynamic: home-page
|
|
27
|
+
Dynamic: license
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
Dynamic: requires-dist
|
|
30
|
+
Dynamic: requires-python
|
|
31
|
+
Dynamic: summary
|
|
32
|
+
|
|
33
|
+
# Flask Session using Azure table storage (Using Azure-Data-Tables Library)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
[](https://pypi.org/project/flask-session-azure/)
|
|
37
|
+
[](https://pypi.org/project/flask-session-azure/)
|
|
38
|
+

|
|
39
|
+
|
|
40
|
+
This module can be used as a Flask Session handler for Azure table storage or Azure CosmosDB.
|
|
41
|
+
All stored data is encrypted using AES encryption.
|
|
42
|
+
|
|
43
|
+
Example usage:
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
import flask
|
|
47
|
+
from flask_session_azure import storage_account_interface
|
|
48
|
+
|
|
49
|
+
app = flask.Flask(__name__)
|
|
50
|
+
app.secret_key = "MyVerySecretEnryptionKeyForEverything" # must be at least 16 characters, the longer the better
|
|
51
|
+
connection_string = "DefaultEndpointsProtocol=https;AccountName=someAccount;AccountKey=someKey;EndpointSuffix=core.windows.net"
|
|
52
|
+
app.session_interface = storage_account_interface(connection_string)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
This will store the session data in a table called `flasksession`, with a partition key called `default_session`. IF the table does not yet exists, it will be created the first time a session is stored.
|
|
56
|
+
You can overwrite these default when creating the session interface:
|
|
57
|
+
```python
|
|
58
|
+
app.session_interface = storage_account_interface(connection_string, table_name="mytablename", partition_key="app1", create_table_if_not_exists=False)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
If you use this in Azure Function, or Azure Web-Service, you most certainly already have a storage account connection in your environment variable `AzureWebJobsStorage`:
|
|
62
|
+
```python
|
|
63
|
+
import os
|
|
64
|
+
import flask
|
|
65
|
+
from flask_session_azure import storage_account_interface
|
|
66
|
+
|
|
67
|
+
app = flask.Flask(__name__)
|
|
68
|
+
app.secret_key = "MyVerySecretEnryptionKeyForEverything" # must be at least 16 characters, the longer the better
|
|
69
|
+
connection_string = os.environ.get("AzureWebjobsStorage")
|
|
70
|
+
app.session_interface = storage_account_interface(connection_string)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Changelog
|
|
74
|
+
|
|
75
|
+
### 0.4.5
|
|
76
|
+
- Edited functions to use updated Azure-Core library instead of deprecated Azure-Common. Updated flask elements to use newer app.config format.
|
|
77
|
+
|
|
78
|
+
### 0.4.4
|
|
79
|
+
- Edited functions to use the Azure-Data-Tables library that is actively maintained by Microsoft
|
|
80
|
+
|
|
81
|
+
### 0.4.3
|
|
82
|
+
- Fixed issue with secret key length and secret key containing non-asci characters
|
|
83
|
+
|
|
84
|
+
### 0.4.2
|
|
85
|
+
- Fixed issue if "samesite" cookie value was not set (i.e. set to none). If it is not set, it is now set to Lax to work in an azure function (see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite)
|
|
86
|
+
|
|
87
|
+
### 0.4.1
|
|
88
|
+
- First public release
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Flask Session using Azure table storage (Using Azure-Data-Tables Library)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
[](https://pypi.org/project/flask-session-azure/)
|
|
5
|
+
[](https://pypi.org/project/flask-session-azure/)
|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
This module can be used as a Flask Session handler for Azure table storage or Azure CosmosDB.
|
|
9
|
+
All stored data is encrypted using AES encryption.
|
|
10
|
+
|
|
11
|
+
Example usage:
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
import flask
|
|
15
|
+
from flask_session_azure import storage_account_interface
|
|
16
|
+
|
|
17
|
+
app = flask.Flask(__name__)
|
|
18
|
+
app.secret_key = "MyVerySecretEnryptionKeyForEverything" # must be at least 16 characters, the longer the better
|
|
19
|
+
connection_string = "DefaultEndpointsProtocol=https;AccountName=someAccount;AccountKey=someKey;EndpointSuffix=core.windows.net"
|
|
20
|
+
app.session_interface = storage_account_interface(connection_string)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
This will store the session data in a table called `flasksession`, with a partition key called `default_session`. IF the table does not yet exists, it will be created the first time a session is stored.
|
|
24
|
+
You can overwrite these default when creating the session interface:
|
|
25
|
+
```python
|
|
26
|
+
app.session_interface = storage_account_interface(connection_string, table_name="mytablename", partition_key="app1", create_table_if_not_exists=False)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
If you use this in Azure Function, or Azure Web-Service, you most certainly already have a storage account connection in your environment variable `AzureWebJobsStorage`:
|
|
30
|
+
```python
|
|
31
|
+
import os
|
|
32
|
+
import flask
|
|
33
|
+
from flask_session_azure import storage_account_interface
|
|
34
|
+
|
|
35
|
+
app = flask.Flask(__name__)
|
|
36
|
+
app.secret_key = "MyVerySecretEnryptionKeyForEverything" # must be at least 16 characters, the longer the better
|
|
37
|
+
connection_string = os.environ.get("AzureWebjobsStorage")
|
|
38
|
+
app.session_interface = storage_account_interface(connection_string)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Changelog
|
|
42
|
+
|
|
43
|
+
### 0.4.5
|
|
44
|
+
- Edited functions to use updated Azure-Core library instead of deprecated Azure-Common. Updated flask elements to use newer app.config format.
|
|
45
|
+
|
|
46
|
+
### 0.4.4
|
|
47
|
+
- Edited functions to use the Azure-Data-Tables library that is actively maintained by Microsoft
|
|
48
|
+
|
|
49
|
+
### 0.4.3
|
|
50
|
+
- Fixed issue with secret key length and secret key containing non-asci characters
|
|
51
|
+
|
|
52
|
+
### 0.4.2
|
|
53
|
+
- Fixed issue if "samesite" cookie value was not set (i.e. set to none). If it is not set, it is now set to Lax to work in an azure function (see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite)
|
|
54
|
+
|
|
55
|
+
### 0.4.1
|
|
56
|
+
- First public release
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
def storage_account_interface(connection_str: str, table_name: str = "flasksession",
|
|
2
|
+
partition_key: str = "default_session", create_table_if_not_exists: bool = True):
|
|
3
|
+
"""
|
|
4
|
+
Creates a Session object as replacement for the default flask session
|
|
5
|
+
The Session uses Azure storage accounts or Azure cosmosDB with Table API as backend
|
|
6
|
+
:param connection_str: Connection string to storage account or CosmosDb with Table-API
|
|
7
|
+
:param table_name: the table name. Default is "flasksession". When overwriting this, follow the table name rules
|
|
8
|
+
https://docs.microsoft.com/en-us/rest/api/storageservices/Understanding-the-Table-Service-Data-Model#table-names
|
|
9
|
+
:param partition_key: the partition key within the table. Use a unique partition_key if applications share a table
|
|
10
|
+
:param create_table_if_not_exists: set to False if you do not want this application to create a table for you
|
|
11
|
+
:return: a Flask session manager
|
|
12
|
+
"""
|
|
13
|
+
from flask_session_azure.storage_account_session import StorageAccountSessionInterface
|
|
14
|
+
return StorageAccountSessionInterface(connection_str, table_name=table_name, partition_key=partition_key,
|
|
15
|
+
create_table_if_not_exists=create_table_if_not_exists)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
from typing import Dict, List, Union, Tuple
|
|
3
|
+
|
|
4
|
+
from Cryptodome.Cipher import AES
|
|
5
|
+
from azure.core.exceptions import ResourceNotFoundError
|
|
6
|
+
from flask.json.tag import TaggedJSONSerializer
|
|
7
|
+
from azure.data.tables import TableClient
|
|
8
|
+
|
|
9
|
+
class StorageAccount(object):
|
|
10
|
+
json_serializer = TaggedJSONSerializer()
|
|
11
|
+
|
|
12
|
+
def __init__(self, connection_str: str, table_name: str, partition_key: str, create_table_if_not_exists: bool):
|
|
13
|
+
self.table_name = table_name
|
|
14
|
+
self.partition_key = partition_key
|
|
15
|
+
self.create_table_if_not_exists = create_table_if_not_exists
|
|
16
|
+
self.table_service = TableClient.from_connection_string(conn_str=connection_str, table_name=self.table_name)
|
|
17
|
+
|
|
18
|
+
def write(self, key: str, data: dict, encryption_key: bytes) -> None:
|
|
19
|
+
"""
|
|
20
|
+
serializes and encrypts the passed dict object object and writes it to the storage
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
data = self.json_serializer.dumps(data)
|
|
24
|
+
encoded_data, tag, nonce = self.encrypt(data, encryption_key)
|
|
25
|
+
entity = {
|
|
26
|
+
"PartitionKey": self.partition_key,
|
|
27
|
+
"RowKey": key,
|
|
28
|
+
"Data": encoded_data,
|
|
29
|
+
"Tag": tag,
|
|
30
|
+
"Nonce": nonce
|
|
31
|
+
}
|
|
32
|
+
try:
|
|
33
|
+
self.table_service.upsert_entity(entity=entity)
|
|
34
|
+
except ResourceNotFoundError:
|
|
35
|
+
if not self.create_table_if_not_exists:
|
|
36
|
+
raise
|
|
37
|
+
self.table_service.create_table()
|
|
38
|
+
self.table_service.upsert_entity(entity=entity)
|
|
39
|
+
|
|
40
|
+
def read(self, key: str, app_key: bytes) -> Union[List[Dict], None]:
|
|
41
|
+
"""
|
|
42
|
+
reads encrypted data from storage and decrypts and deserializes it.
|
|
43
|
+
Returns None if no data was found or decryption failed.
|
|
44
|
+
"""
|
|
45
|
+
try:
|
|
46
|
+
data = self.table_service.get_entity(self.partition_key, key)
|
|
47
|
+
decoded = self.decrypt(data["Data"], data["Tag"], data["Nonce"], app_key)
|
|
48
|
+
if decoded is not None:
|
|
49
|
+
return self.json_serializer.loads(decoded)
|
|
50
|
+
return None
|
|
51
|
+
except ResourceNotFoundError:
|
|
52
|
+
return None
|
|
53
|
+
|
|
54
|
+
def delete(self, key: str) -> None:
|
|
55
|
+
"""
|
|
56
|
+
Removes an element from storage if it exists
|
|
57
|
+
"""
|
|
58
|
+
try:
|
|
59
|
+
self.table_service.delete_entity(self.partition_key, key)
|
|
60
|
+
except ResourceNotFoundError:
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
@staticmethod
|
|
64
|
+
def encrypt(data: str, secret_text: bytes) -> Tuple[str, str, str]:
|
|
65
|
+
"""
|
|
66
|
+
encrypts the passed data with the secret text.
|
|
67
|
+
:return: a tuple of three elements: encrypted data, verification_tag and nonce element.
|
|
68
|
+
All elements are base64 encoded strings
|
|
69
|
+
"""
|
|
70
|
+
cipher = AES.new(secret_text, AES.MODE_EAX)
|
|
71
|
+
ciphertext, tag = cipher.encrypt_and_digest((data.encode("utf-8")))
|
|
72
|
+
return (base64.b64encode(ciphertext).decode("ascii"),
|
|
73
|
+
base64.b64encode(tag).decode("ascii"),
|
|
74
|
+
base64.b64encode(cipher.nonce).decode("ascii"))
|
|
75
|
+
|
|
76
|
+
@staticmethod
|
|
77
|
+
def decrypt(encrypted_data: str, verification_tag: str, nonce: str, secret_text: bytes) -> Union[str, None]:
|
|
78
|
+
"""
|
|
79
|
+
Decrypts encoded data using the passed secret_text
|
|
80
|
+
:param encrypted_data: as base64 encoded string or byte array
|
|
81
|
+
:param verification_tag: as base64 encoded string or byte array
|
|
82
|
+
:param nonce: as base64 encoded string or byte array
|
|
83
|
+
:param secret_text: the same secret text with wich the element was encoded
|
|
84
|
+
:return: the plaintext on success, None if the data could not be decoded or verified
|
|
85
|
+
"""
|
|
86
|
+
nonce = base64.b64decode(nonce)
|
|
87
|
+
cipher = AES.new(secret_text, AES.MODE_EAX, nonce=nonce)
|
|
88
|
+
data = base64.b64decode(encrypted_data)
|
|
89
|
+
plaintext = cipher.decrypt(data)
|
|
90
|
+
tag = base64.b64decode(verification_tag)
|
|
91
|
+
try:
|
|
92
|
+
cipher.verify(tag)
|
|
93
|
+
return plaintext.decode("utf-8")
|
|
94
|
+
except ValueError:
|
|
95
|
+
return None
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
from uuid import uuid4
|
|
2
|
+
|
|
3
|
+
import flask
|
|
4
|
+
from flask.sessions import SessionMixin, SessionInterface
|
|
5
|
+
from werkzeug.datastructures import CallbackDict
|
|
6
|
+
|
|
7
|
+
from flask_session_azure.storage_account import StorageAccount
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class StorageAccountSession(CallbackDict, SessionMixin):
|
|
11
|
+
def __init__(self, sid: str, initial=None):
|
|
12
|
+
def on_update(self):
|
|
13
|
+
self.modified = True
|
|
14
|
+
|
|
15
|
+
CallbackDict.__init__(self, initial, on_update)
|
|
16
|
+
self.sid = sid
|
|
17
|
+
self.modified = False
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class StorageAccountSessionInterface(SessionInterface):
|
|
21
|
+
"""
|
|
22
|
+
Replacement session interface for flask that uses Azure-Storage account tables as storage backend
|
|
23
|
+
Data is encrypted and tagged for manipulation using AES encryption
|
|
24
|
+
"""
|
|
25
|
+
session_class = StorageAccountSession
|
|
26
|
+
|
|
27
|
+
def __init__(self, connection_str: str, table_name="flasksession", partition_key="default_session",
|
|
28
|
+
create_table_if_not_exists: bool = True):
|
|
29
|
+
"""
|
|
30
|
+
:param connection_str: the connection string to the azure table storage (or cosmos db)
|
|
31
|
+
:param table_name: the table name. Default is "flasksession". When overwriting this, follow the table name rules
|
|
32
|
+
https://docs.microsoft.com/en-us/rest/api/storageservices/Understanding-the-Table-Service-Data-Model#table-names
|
|
33
|
+
:param partition_key: the partition key within the table. Use a unique partition_key if applications share a table
|
|
34
|
+
"""
|
|
35
|
+
self.storage = StorageAccount(connection_str, table_name, partition_key, create_table_if_not_exists)
|
|
36
|
+
|
|
37
|
+
@staticmethod
|
|
38
|
+
def get_encryption_key_from_app_secret(app) -> bytes:
|
|
39
|
+
"""
|
|
40
|
+
Checks if the app secret_key is set, and if it is long enough to use it as AES encryption key.
|
|
41
|
+
Returns the key truncated to a length of multiples of 8, to use it as AES encryption key
|
|
42
|
+
"""
|
|
43
|
+
if app.secret_key is None:
|
|
44
|
+
raise RuntimeError(
|
|
45
|
+
"The session is unavailable because no secret key was set. "
|
|
46
|
+
"Set the secret_key on the application to something unique and secret.")
|
|
47
|
+
try:
|
|
48
|
+
# if secret_text is a string, make it bytes
|
|
49
|
+
secret_key = app.secret_key.encode("utf-8")
|
|
50
|
+
except AttributeError:
|
|
51
|
+
secret_key = app.secret_key
|
|
52
|
+
|
|
53
|
+
if len(secret_key) < 16:
|
|
54
|
+
raise RuntimeError(
|
|
55
|
+
"The session is unavailable because the secret is too short. "
|
|
56
|
+
f"The secret must be 16 characters or longer, but is only {len(app.secret_key)} character(s).")
|
|
57
|
+
|
|
58
|
+
# only use multiples of 8 from the secret_key tu use it as AES encryption_key
|
|
59
|
+
characters = len(app.secret_key)
|
|
60
|
+
characters = min(32, characters - characters % 8)
|
|
61
|
+
return secret_key[:characters]
|
|
62
|
+
|
|
63
|
+
def open_session(self, app: flask.Flask, request: flask.Request) -> StorageAccountSession:
|
|
64
|
+
"""
|
|
65
|
+
Reads the session data from table storage, decrypts the data and returns the session object
|
|
66
|
+
"""
|
|
67
|
+
sid = request.cookies.get(app.config["SESSION_COOKIE_NAME"])
|
|
68
|
+
if not sid:
|
|
69
|
+
sid = str(uuid4())
|
|
70
|
+
return self.session_class(sid=sid)
|
|
71
|
+
encryption_key = self.get_encryption_key_from_app_secret(app)
|
|
72
|
+
data = self.storage.read(sid, encryption_key)
|
|
73
|
+
if data is not None:
|
|
74
|
+
return self.session_class(sid=sid, initial=data)
|
|
75
|
+
return self.session_class(sid=sid)
|
|
76
|
+
|
|
77
|
+
def save_session(self, app: flask.Flask, session: StorageAccountSession, response: flask.Response) -> None:
|
|
78
|
+
"""
|
|
79
|
+
Serializes the data to JSON, encrypts the data using AES
|
|
80
|
+
and stores the encrypted data along with a verification tag to azure storage.
|
|
81
|
+
Only stores the UUID of the table entry inside the session_cookie
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
domain = self.get_cookie_domain(app)
|
|
85
|
+
path = self.get_cookie_path(app)
|
|
86
|
+
if not session:
|
|
87
|
+
if session.modified:
|
|
88
|
+
self.storage.delete(session.sid)
|
|
89
|
+
response.delete_cookie(app.config["SESSION_COOKIE_NAME"], domain=domain, path=path)
|
|
90
|
+
return
|
|
91
|
+
|
|
92
|
+
if session.modified:
|
|
93
|
+
encryption_key = self.get_encryption_key_from_app_secret(app)
|
|
94
|
+
self.storage.write(session.sid, dict(session), encryption_key)
|
|
95
|
+
httponly = True
|
|
96
|
+
secure = self.get_cookie_secure(app)
|
|
97
|
+
samesite = self.get_cookie_samesite(app)
|
|
98
|
+
if samesite is None:
|
|
99
|
+
samesite = 'Lax'
|
|
100
|
+
expires = self.get_expiration_time(app, session)
|
|
101
|
+
response.set_cookie(app.config["SESSION_COOKIE_NAME"], session.sid, expires=expires, httponly=httponly, domain=domain,
|
|
102
|
+
path=path, secure=secure, samesite=samesite)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flask_session_azure_c
|
|
3
|
+
Version: 0.4.6
|
|
4
|
+
Summary: Flask Session using Azure Table Storage or CosmosDB table API
|
|
5
|
+
Home-page: https://github.com/bassmandan/FlaskAzureTableSession
|
|
6
|
+
Author: Claas Diederichs, Daniel Harding
|
|
7
|
+
Author-email:
|
|
8
|
+
License: MIT
|
|
9
|
+
Classifier: Framework :: Flask
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Requires-Python: >=3.6
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: azure-data-tables
|
|
20
|
+
Requires-Dist: pycryptodomex>=3.9.7
|
|
21
|
+
Requires-Dist: flask
|
|
22
|
+
Dynamic: author
|
|
23
|
+
Dynamic: classifier
|
|
24
|
+
Dynamic: description
|
|
25
|
+
Dynamic: description-content-type
|
|
26
|
+
Dynamic: home-page
|
|
27
|
+
Dynamic: license
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
Dynamic: requires-dist
|
|
30
|
+
Dynamic: requires-python
|
|
31
|
+
Dynamic: summary
|
|
32
|
+
|
|
33
|
+
# Flask Session using Azure table storage (Using Azure-Data-Tables Library)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
[](https://pypi.org/project/flask-session-azure/)
|
|
37
|
+
[](https://pypi.org/project/flask-session-azure/)
|
|
38
|
+

|
|
39
|
+
|
|
40
|
+
This module can be used as a Flask Session handler for Azure table storage or Azure CosmosDB.
|
|
41
|
+
All stored data is encrypted using AES encryption.
|
|
42
|
+
|
|
43
|
+
Example usage:
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
import flask
|
|
47
|
+
from flask_session_azure import storage_account_interface
|
|
48
|
+
|
|
49
|
+
app = flask.Flask(__name__)
|
|
50
|
+
app.secret_key = "MyVerySecretEnryptionKeyForEverything" # must be at least 16 characters, the longer the better
|
|
51
|
+
connection_string = "DefaultEndpointsProtocol=https;AccountName=someAccount;AccountKey=someKey;EndpointSuffix=core.windows.net"
|
|
52
|
+
app.session_interface = storage_account_interface(connection_string)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
This will store the session data in a table called `flasksession`, with a partition key called `default_session`. IF the table does not yet exists, it will be created the first time a session is stored.
|
|
56
|
+
You can overwrite these default when creating the session interface:
|
|
57
|
+
```python
|
|
58
|
+
app.session_interface = storage_account_interface(connection_string, table_name="mytablename", partition_key="app1", create_table_if_not_exists=False)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
If you use this in Azure Function, or Azure Web-Service, you most certainly already have a storage account connection in your environment variable `AzureWebJobsStorage`:
|
|
62
|
+
```python
|
|
63
|
+
import os
|
|
64
|
+
import flask
|
|
65
|
+
from flask_session_azure import storage_account_interface
|
|
66
|
+
|
|
67
|
+
app = flask.Flask(__name__)
|
|
68
|
+
app.secret_key = "MyVerySecretEnryptionKeyForEverything" # must be at least 16 characters, the longer the better
|
|
69
|
+
connection_string = os.environ.get("AzureWebjobsStorage")
|
|
70
|
+
app.session_interface = storage_account_interface(connection_string)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Changelog
|
|
74
|
+
|
|
75
|
+
### 0.4.5
|
|
76
|
+
- Edited functions to use updated Azure-Core library instead of deprecated Azure-Common. Updated flask elements to use newer app.config format.
|
|
77
|
+
|
|
78
|
+
### 0.4.4
|
|
79
|
+
- Edited functions to use the Azure-Data-Tables library that is actively maintained by Microsoft
|
|
80
|
+
|
|
81
|
+
### 0.4.3
|
|
82
|
+
- Fixed issue with secret key length and secret key containing non-asci characters
|
|
83
|
+
|
|
84
|
+
### 0.4.2
|
|
85
|
+
- Fixed issue if "samesite" cookie value was not set (i.e. set to none). If it is not set, it is now set to Lax to work in an azure function (see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite)
|
|
86
|
+
|
|
87
|
+
### 0.4.1
|
|
88
|
+
- First public release
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
setup.py
|
|
4
|
+
flask_session_azure/__init__.py
|
|
5
|
+
flask_session_azure/storage_account.py
|
|
6
|
+
flask_session_azure/storage_account_session.py
|
|
7
|
+
flask_session_azure_c.egg-info/PKG-INFO
|
|
8
|
+
flask_session_azure_c.egg-info/SOURCES.txt
|
|
9
|
+
flask_session_azure_c.egg-info/dependency_links.txt
|
|
10
|
+
flask_session_azure_c.egg-info/requires.txt
|
|
11
|
+
flask_session_azure_c.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
flask_session_azure
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
|
|
3
|
+
with open("README.md", "r") as fh:
|
|
4
|
+
long_description = fh.read()
|
|
5
|
+
|
|
6
|
+
setup(
|
|
7
|
+
name='flask_session_azure_c',
|
|
8
|
+
version='0.4.6',
|
|
9
|
+
packages=['flask_session_azure'],
|
|
10
|
+
url='https://github.com/bassmandan/FlaskAzureTableSession',
|
|
11
|
+
license='MIT',
|
|
12
|
+
author='Claas Diederichs, Daniel Harding',
|
|
13
|
+
author_email='',
|
|
14
|
+
description='Flask Session using Azure Table Storage or CosmosDB table API',
|
|
15
|
+
long_description=long_description,
|
|
16
|
+
long_description_content_type="text/markdown",
|
|
17
|
+
classifiers=[
|
|
18
|
+
"Framework :: Flask",
|
|
19
|
+
"Programming Language :: Python :: 3.6",
|
|
20
|
+
"Programming Language :: Python :: 3.7",
|
|
21
|
+
"Programming Language :: Python :: 3.8",
|
|
22
|
+
"Programming Language :: Python :: 3.9",
|
|
23
|
+
"License :: OSI Approved :: MIT License",
|
|
24
|
+
"Operating System :: OS Independent",
|
|
25
|
+
],
|
|
26
|
+
python_requires='>=3.6',
|
|
27
|
+
install_requires=[
|
|
28
|
+
"azure-data-tables",
|
|
29
|
+
"pycryptodomex>=3.9.7",
|
|
30
|
+
"flask"
|
|
31
|
+
]
|
|
32
|
+
)
|