okta-expression-parser 0.2.2__tar.gz → 0.4.0__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.
- {okta_expression_parser-0.2.2 → okta_expression_parser-0.4.0}/PKG-INFO +1 -1
- {okta_expression_parser-0.2.2 → okta_expression_parser-0.4.0}/okta_expression_parser/lexer.py +15 -2
- {okta_expression_parser-0.2.2 → okta_expression_parser-0.4.0}/okta_expression_parser/parser.py +89 -20
- {okta_expression_parser-0.2.2 → okta_expression_parser-0.4.0}/pyproject.toml +1 -1
- {okta_expression_parser-0.2.2 → okta_expression_parser-0.4.0}/README.md +0 -0
- {okta_expression_parser-0.2.2 → okta_expression_parser-0.4.0}/okta_expression_parser/__init__.py +0 -0
- {okta_expression_parser-0.2.2 → okta_expression_parser-0.4.0}/okta_expression_parser/expression_classes/__init__.py +0 -0
- {okta_expression_parser-0.2.2 → okta_expression_parser-0.4.0}/okta_expression_parser/expression_classes/arrays.py +0 -0
- {okta_expression_parser-0.2.2 → okta_expression_parser-0.4.0}/okta_expression_parser/expression_classes/convert.py +0 -0
- {okta_expression_parser-0.2.2 → okta_expression_parser-0.4.0}/okta_expression_parser/expression_classes/groups.py +0 -0
- {okta_expression_parser-0.2.2 → okta_expression_parser-0.4.0}/okta_expression_parser/expression_classes/iso3166convert.py +0 -0
- {okta_expression_parser-0.2.2 → okta_expression_parser-0.4.0}/okta_expression_parser/expression_classes/string.py +0 -0
{okta_expression_parser-0.2.2 → okta_expression_parser-0.4.0}/okta_expression_parser/lexer.py
RENAMED
|
@@ -10,9 +10,9 @@ class ExpressionLexer(Lexer):
|
|
|
10
10
|
# reflags = re.IGNORECASE
|
|
11
11
|
# Set of token names.
|
|
12
12
|
tokens = {
|
|
13
|
+
NAME,
|
|
13
14
|
STRING,
|
|
14
15
|
INT,
|
|
15
|
-
NAME,
|
|
16
16
|
NE,
|
|
17
17
|
GTE,
|
|
18
18
|
LTE,
|
|
@@ -24,8 +24,14 @@ class ExpressionLexer(Lexer):
|
|
|
24
24
|
NOT,
|
|
25
25
|
NULL,
|
|
26
26
|
BOOL,
|
|
27
|
+
COLON,
|
|
28
|
+
QUESTION_MARK,
|
|
27
29
|
MEMBEROF,
|
|
28
30
|
MEMBEROFANY,
|
|
31
|
+
MEMBEROFNAME,
|
|
32
|
+
MEMBEROFGROUPSTARTSWITH,
|
|
33
|
+
MEMBEROFGROUPCONTAINS,
|
|
34
|
+
MEMBEROFGROUPNAMEREGEX,
|
|
29
35
|
USER,
|
|
30
36
|
CLASS,
|
|
31
37
|
}
|
|
@@ -46,14 +52,21 @@ class ExpressionLexer(Lexer):
|
|
|
46
52
|
OR = r"or|OR|Or"
|
|
47
53
|
EQ = r"(==|eq|EQ|Eq)"
|
|
48
54
|
BOOL = r"(true|false|True|False|TRUE|FALSE)"
|
|
55
|
+
MEMBEROFGROUPCONTAINS = "isMemberOfGroupNameContains"
|
|
56
|
+
MEMBEROFGROUPNAMEREGEX = "isMemberOfGroupNameRegex"
|
|
57
|
+
MEMBEROFGROUPSTARTSWITH = "isMemberOfGroupNameStartsWith"
|
|
49
58
|
MEMBEROFANY = "isMemberOfAnyGroup"
|
|
59
|
+
MEMBEROFNAME = "isMemberOfGroupName"
|
|
50
60
|
MEMBEROF = "isMemberOfGroup"
|
|
51
61
|
USER = r"user\b"
|
|
62
|
+
COLON = r"\:"
|
|
63
|
+
QUESTION_MARK = r"\?"
|
|
52
64
|
|
|
53
65
|
NULL = r"null|NULL|Null"
|
|
54
66
|
CLASS = r"String|Arrays|Convert|Iso3166Convert|Groups"
|
|
55
67
|
INT = r"\d+"
|
|
56
|
-
STRING = r""""([^"\\]*(\\.[^"\\]*)*)"|\'([^\'\\]*(\\.[^\'\\]*)*)\'|''|\"\""""
|
|
68
|
+
# STRING = r""""([^"\\]*(\\.[^"\\]*)*)"|\'([^\'\\]*(\\.[^\'\\]*)*)\'|''|\"\""""
|
|
69
|
+
STRING = r'''"(?:\\.|[^"\\])*"'''
|
|
57
70
|
NAME = r"[a-zA-Z_][a-zA-Z0-9\-_]*"
|
|
58
71
|
|
|
59
72
|
# Line number tracking
|
{okta_expression_parser-0.2.2 → okta_expression_parser-0.4.0}/okta_expression_parser/parser.py
RENAMED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# pyright: reportUndefinedVariable=false
|
|
2
2
|
import logging
|
|
3
3
|
from os import environ
|
|
4
|
+
from re import match
|
|
4
5
|
from sys import stdout
|
|
5
6
|
from typing import Any, Dict, List, Sequence
|
|
6
7
|
from types import ModuleType
|
|
@@ -14,9 +15,8 @@ from .lexer import ExpressionLexer
|
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
class ExpressionParser(sly.Parser):
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
debugfile: str = environ.get(debug_file)
|
|
18
|
+
#: Writes grammar rules to a file for debugging
|
|
19
|
+
debugfile = environ.get("OKTA_EXPRESSION_PARSER_LOG_FILE")
|
|
20
20
|
|
|
21
21
|
#: Gets the token list from the lexer (required)
|
|
22
22
|
tokens: Sequence = ExpressionLexer.tokens
|
|
@@ -50,6 +50,7 @@ class ExpressionParser(sly.Parser):
|
|
|
50
50
|
):
|
|
51
51
|
self._expression_classes.Groups.group_data = group_data
|
|
52
52
|
|
|
53
|
+
#: A dict, with Group ID's as the keys and group data as the values. Used for operations that require more context than just the group ID.
|
|
53
54
|
self.group_data = group_data
|
|
54
55
|
|
|
55
56
|
self.__group_ids: str = group_ids
|
|
@@ -64,6 +65,12 @@ class ExpressionParser(sly.Parser):
|
|
|
64
65
|
def parse(self, expression: str):
|
|
65
66
|
return super().parse(ExpressionLexer().tokenize(expression))
|
|
66
67
|
|
|
68
|
+
@_("operand") # noqa: 821
|
|
69
|
+
@_("condition") # noqa: 821
|
|
70
|
+
def result(self, p: YaccProduction) -> bool: # noqa: 811
|
|
71
|
+
res = p.condition if hasattr(p, "condition") else p.operand
|
|
72
|
+
return res
|
|
73
|
+
|
|
67
74
|
@_("operand EQ operand") # noqa: 821
|
|
68
75
|
def condition(self, p: YaccProduction) -> bool:
|
|
69
76
|
operand0 = p.operand0
|
|
@@ -107,17 +114,39 @@ class ExpressionParser(sly.Parser):
|
|
|
107
114
|
operand1 = p.operand1
|
|
108
115
|
return type(operand0) == type(operand1) and operand0 > operand1
|
|
109
116
|
|
|
117
|
+
@_('"(" condition ")"') # noqa: 821
|
|
118
|
+
def condition(self, p: YaccProduction) -> bool: # noqa: 811
|
|
119
|
+
return p.condition
|
|
120
|
+
|
|
121
|
+
@_('"(" operand ")"') # noqa: 821
|
|
122
|
+
def operand(self, p: YaccProduction) -> bool: # noqa: 811
|
|
123
|
+
return p.operand
|
|
124
|
+
|
|
110
125
|
@_("condition AND condition") # noqa: 821
|
|
111
126
|
def condition(self, p: YaccProduction) -> bool: # noqa: 811
|
|
112
|
-
condition0
|
|
113
|
-
|
|
114
|
-
|
|
127
|
+
return p.condition0 and p.condition1
|
|
128
|
+
|
|
129
|
+
@_("operand AND operand") # noqa: 821
|
|
130
|
+
def condition(self, p: YaccProduction) -> bool: # noqa: 811
|
|
131
|
+
return p.operand0 and p.operand1
|
|
132
|
+
|
|
133
|
+
@_("operand AND condition") # noqa: 821
|
|
134
|
+
@_("condition AND operand") # noqa: 821
|
|
135
|
+
def condition(self, p: YaccProduction) -> bool: # noqa: 811
|
|
136
|
+
return p.condition and p.operand
|
|
115
137
|
|
|
116
138
|
@_("condition OR condition") # noqa: 821
|
|
117
139
|
def condition(self, p: YaccProduction) -> bool: # noqa: 811
|
|
118
|
-
condition0
|
|
119
|
-
|
|
120
|
-
|
|
140
|
+
return p.condition0 or p.condition1
|
|
141
|
+
|
|
142
|
+
@_("operand OR operand") # noqa: 821
|
|
143
|
+
def condition(self, p: YaccProduction) -> bool: # noqa: 811
|
|
144
|
+
return p.operand0 or p.operand1
|
|
145
|
+
|
|
146
|
+
@_("operand OR condition") # noqa: 821
|
|
147
|
+
@_("condition OR operand") # noqa: 821
|
|
148
|
+
def condition(self, p: YaccProduction) -> bool: # noqa: 811
|
|
149
|
+
return p.condition or p.operand
|
|
121
150
|
|
|
122
151
|
@_("NOT condition") # noqa: 821
|
|
123
152
|
def condition(self, p: YaccProduction) -> bool: # noqa: 811
|
|
@@ -128,22 +157,11 @@ class ExpressionParser(sly.Parser):
|
|
|
128
157
|
def condition(self, p: YaccProduction) -> bool: # noqa: 811
|
|
129
158
|
return not p.operand
|
|
130
159
|
|
|
131
|
-
@_('"(" condition ")"') # noqa: 821
|
|
132
|
-
def condition(self, p: YaccProduction) -> bool: # noqa: 811
|
|
133
|
-
condition = p.condition
|
|
134
|
-
return condition
|
|
135
|
-
|
|
136
160
|
@_('operand "," operand') # noqa: 821
|
|
137
161
|
def operand(self, p: YaccProduction) -> List[Any]: # noqa: 811
|
|
138
162
|
operand0 = p.operand0
|
|
139
163
|
operand1 = p.operand1
|
|
140
164
|
|
|
141
|
-
# if not isinstance(operand0, tuple):
|
|
142
|
-
# return (operand0, operand1)
|
|
143
|
-
#
|
|
144
|
-
# else:
|
|
145
|
-
# return operand0 + (operand1,)
|
|
146
|
-
|
|
147
165
|
if isinstance(operand0, tuple) and isinstance(operand1, tuple):
|
|
148
166
|
res = operand0 + operand1
|
|
149
167
|
elif isinstance(operand0, tuple) and not isinstance(operand1, tuple):
|
|
@@ -309,6 +327,57 @@ class ExpressionParser(sly.Parser):
|
|
|
309
327
|
|
|
310
328
|
return p.operand in self.__group_ids
|
|
311
329
|
|
|
330
|
+
@_('MEMBEROFNAME "(" operand ")"')
|
|
331
|
+
def condition(self, p: YaccProduction):
|
|
332
|
+
"""Tests if a user is a member of a group with a specific name"""
|
|
333
|
+
|
|
334
|
+
matches = [
|
|
335
|
+
v for k, v in self.group_data.items() if v["profile"]["name"] == p.operand
|
|
336
|
+
]
|
|
337
|
+
|
|
338
|
+
return bool(matches)
|
|
339
|
+
|
|
340
|
+
@_('MEMBEROFGROUPSTARTSWITH "(" operand ")"')
|
|
341
|
+
def condition(self, p: YaccProduction):
|
|
342
|
+
"""Tests if a user is a member of a group with a specific name"""
|
|
343
|
+
|
|
344
|
+
matches = [
|
|
345
|
+
v
|
|
346
|
+
for k, v in self.group_data.items()
|
|
347
|
+
if v["profile"]["name"].startswith(p.operand)
|
|
348
|
+
]
|
|
349
|
+
|
|
350
|
+
return bool(matches)
|
|
351
|
+
|
|
352
|
+
@_('MEMBEROFGROUPCONTAINS "(" operand ")"')
|
|
353
|
+
def condition(self, p: YaccProduction):
|
|
354
|
+
"""Tests if a user is a member of a group with a specific name"""
|
|
355
|
+
|
|
356
|
+
matches = [
|
|
357
|
+
v for k, v in self.group_data.items() if p.operand in v["profile"]["name"]
|
|
358
|
+
]
|
|
359
|
+
|
|
360
|
+
return bool(matches)
|
|
361
|
+
|
|
362
|
+
@_('MEMBEROFGROUPNAMEREGEX "(" operand ")"')
|
|
363
|
+
def condition(self, p: YaccProduction):
|
|
364
|
+
"""Tests if a user is a member of a group with a specific name"""
|
|
365
|
+
|
|
366
|
+
for _, group in self.group_data.items():
|
|
367
|
+
if match(p.operand, group["profile"]["name"]):
|
|
368
|
+
return True
|
|
369
|
+
|
|
370
|
+
return False
|
|
371
|
+
|
|
372
|
+
@_("operand QUESTION_MARK operand COLON operand") # noqa: 821
|
|
373
|
+
@_("condition QUESTION_MARK operand COLON operand") # noqa: 821
|
|
374
|
+
def operand(self, p: YaccProduction) -> Any: # noqa: 811
|
|
375
|
+
condition = p.condition if hasattr(p, "condition") else p.operand0
|
|
376
|
+
if_true = p.operand0 if hasattr(p, "condition") else p.operand1
|
|
377
|
+
if_false = p.operand1 if hasattr(p, "condition") else p.operand2
|
|
378
|
+
|
|
379
|
+
return if_true if condition else if_false
|
|
380
|
+
|
|
312
381
|
@_("condition error") # noqa: 821
|
|
313
382
|
def operand(self, x): # noqa: 811
|
|
314
383
|
raise SyntaxError(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "okta-expression-parser"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.4.0"
|
|
4
4
|
description = "Returns a boolean by passing Okta profile data to an Okta Expression using Okta Expression Language"
|
|
5
5
|
authors = ["Mathew Moon <me@mathewmoon.net>"]
|
|
6
6
|
readme = "README.md"
|
|
File without changes
|
{okta_expression_parser-0.2.2 → okta_expression_parser-0.4.0}/okta_expression_parser/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|