-
Notifications
You must be signed in to change notification settings - Fork 124
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #113 from c00kiemon5ter/feature-microservice-attri…
…bute-processor Add attribute processor microservice
- Loading branch information
Showing
7 changed files
with
169 additions
and
0 deletions.
There are no files selected for viewing
17 changes: 17 additions & 0 deletions
17
example/plugins/microservices/attribute_processor.yaml.example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
module: satosa.micro_services.attribute_processor.AttributeProcessor | ||
name: AttributeProcessor | ||
config: | ||
process: | ||
- attribute: gender | ||
processors: | ||
- name: GenderToSchacProcessor | ||
module: satosa.micro_services.processors.gender_processor | ||
- attribute: identifier | ||
processors: | ||
- name: HashProcessor | ||
module: satosa.micro_services.processors.hash_processor | ||
hash_alg: sha256 | ||
salt: abcdef0123456789 | ||
- name: ScopeProcessor | ||
module: satosa.micro_services.processors.scope_processor | ||
scope: example.com |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import importlib | ||
import json | ||
import logging | ||
|
||
from satosa.exception import SATOSAError | ||
from satosa.logging_util import satosa_logging | ||
from satosa.micro_services.base import ResponseMicroService | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
CONFIG_KEY_ROOT = 'process' | ||
CONFIG_KEY_MODULE = 'module' | ||
CONFIG_KEY_CLASSNAME = 'name' | ||
CONFIG_KEY_ATTRIBUTE = 'attribute' | ||
CONFIG_KEY_PROCESSORS = 'processors' | ||
|
||
|
||
class AttributeProcessor(ResponseMicroService): | ||
""" | ||
This microservice enables users to define modules that process internal | ||
attributes and their values. | ||
Example configuration: | ||
# file: attribute_processor.yaml | ||
module: satosa.micro_services.attribute_processor.AttributeProcessor | ||
process: | ||
- attribute: gender | ||
- name: GenderToSchacProcessor | ||
module: satosa.micro_services.processors.gender_processor | ||
- attribute: identifier | ||
processors: | ||
- name: HashProcessor | ||
module: satosa.micro_services.processors.hash_processor | ||
hash_alg: sha256 | ||
salt: abcdef0123456789 | ||
- name: ScopeProcessor | ||
module: satosa.micro_services.processors.scope_processor | ||
scope: example | ||
""" | ||
def __init__(self, config, *args, **kwargs): | ||
super().__init__(*args, **kwargs) | ||
self.config = config | ||
self.processes = config[CONFIG_KEY_ROOT] | ||
|
||
def process(self, context, data): | ||
for process in self.processes: | ||
attribute = process[CONFIG_KEY_ATTRIBUTE] | ||
processors = process[CONFIG_KEY_PROCESSORS] | ||
for processor in processors: | ||
module = importlib.import_module(processor[CONFIG_KEY_MODULE]) | ||
module_cls = getattr(module, processor[CONFIG_KEY_CLASSNAME]) | ||
instance = module_cls() | ||
|
||
kwargs = processor.copy() | ||
kwargs.pop(CONFIG_KEY_MODULE) | ||
kwargs.pop(CONFIG_KEY_CLASSNAME) | ||
|
||
try: | ||
instance.process(data, attribute, **kwargs) | ||
except AttributeProcessorWarning as w: | ||
satosa_logging(logger, logging.WARNING, w, context.state) | ||
|
||
return super().process(context, data) | ||
|
||
|
||
class AttributeProcessorWarning(SATOSAError): | ||
pass | ||
|
||
|
||
class AttributeProcessorError(SATOSAError): | ||
pass |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
class BaseProcessor(object): | ||
def __init__(self): | ||
pass | ||
|
||
def process(internal_data, attribute, **kwargs): | ||
pass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
from .base_processor import BaseProcessor | ||
|
||
from enum import Enum, unique | ||
|
||
|
||
@unique | ||
class Gender(Enum): | ||
NOT_KNOWN = 0 | ||
MALE = 1 | ||
FEMALE = 2 | ||
NOT_SPECIFIED = 9 | ||
|
||
|
||
class GenderToSchacProcessor(BaseProcessor): | ||
def process(self, internal_data, attribute, **kwargs): | ||
attributes = internal_data.attributes | ||
value = attributes.get(attribute, [None])[0] | ||
|
||
if value: | ||
representation = getattr( | ||
Gender, value.upper().replace(' ', '_'), Gender.NOT_KNOWN) | ||
else: | ||
representation = Gender.NOT_SPECIFIED | ||
|
||
attributes[attribute][0] = str(representation.value) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
from ..attribute_processor import AttributeProcessorError | ||
from .base_processor import BaseProcessor | ||
|
||
import hashlib | ||
|
||
|
||
CONFIG_KEY_SALT = 'salt' | ||
CONFIG_DEFAULT_SALT = '' | ||
CONFIG_KEY_HASHALGO = 'hash_algo' | ||
CONFIG_DEFAULT_HASHALGO = 'sha256' | ||
|
||
|
||
class HashProcessor(BaseProcessor): | ||
def process(self, internal_data, attribute, **kwargs): | ||
salt = kwargs.get(CONFIG_KEY_HASHALGO, CONFIG_DEFAULT_SALT) | ||
hash_algo = kwargs.get(CONFIG_KEY_HASHALGO, CONFIG_DEFAULT_HASHALGO) | ||
if hash_algo not in hashlib.algorithms_available: | ||
raise AttributeProcessorError( | ||
"Hash algorithm not supported: {}".format(hash_algo)) | ||
|
||
attributes = internal_data.attributes | ||
value = attributes.get(attribute, [None])[0] | ||
if value is None: | ||
raise AttributeProcessorError( | ||
"No value for attribute: {}".format(attribute)) | ||
|
||
hasher = hashlib.new(hash_algo) | ||
hasher.update(value.encode('utf-8')) | ||
hasher.update(salt.encode('utf-8')) | ||
value_hashed = hasher.hexdigest() | ||
attributes[attribute][0] = value_hashed |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
from ..attribute_processor import AttributeProcessorError | ||
from .base_processor import BaseProcessor | ||
|
||
|
||
CONFIG_KEY_SCOPE = 'scope' | ||
CONFIG_DEFAULT_SCOPE = '' | ||
|
||
|
||
class ScopeProcessor(BaseProcessor): | ||
def process(self, internal_data, attribute, **kwargs): | ||
scope = kwargs.get(CONFIG_KEY_SCOPE, CONFIG_DEFAULT_SCOPE) | ||
if scope is None or scope == '': | ||
raise AttributeProcessorError("No scope set.") | ||
|
||
attributes = internal_data.attributes | ||
value = attributes.get(attribute, [None])[0] | ||
attributes[attribute][0] = value + '@' + scope |