This service implements the communication between the plug-ins, the token storage, the Research Manager and the ports, among other things by implementing the Oauth2 code exchange workflow and thereby generating and storing the access and refresh token in the token storage and creating projects and storing services.
Communication with the plugins
Due to the high relevance of the central service Token Storage, a direct communication between these and the outside world should be prevented. For this purpose the user can use the Port service in the second circle, which addresses the functions for the user of the central service in the third circle. For convenience, many concepts are again abstracted away so that the handling remains very convenient and simple. The service also handles the entire server part of the OAuth workflow.
The plug-ins must follow the sequence diagram below so that it can store a user’s credentials for a service to be connected in the RDS system
sequenceDiagram
participant U as User
participant P as Plugin
participant UC as Use-Case
participant ES as External Service
Note over U,ES: User wants to add a service to RDS
U ->> P: get all servicenames with authorize-url
activate P
P ->> UC: make request /service
activate UC
UC -->> P: returns list with services
deactivate UC
P -->> U: Show dropdown menu with services
deactivate P
Note over U,ES: User selects a service
U ->> P: clicks entry for "exampleService
activate P
P -->> U: PopUp(exampleService["authorize-url"]&state=JWT)
deactivate P
U ->> ES: Logging in
activate ES
ES -->> U: Redirects user with authorization-code to redirect-uri
deactivate ES
U ->> UC: Call redirects-uri with arguments: state, code
activate UC
UC ->> UC: Check arguments: state, code
UC ->> U: Redirects user to success or cancel page
deactivate UC
The state argument, like the code argument, is forwarded using query parameters. The plugin takes the JWT from the service data. Using the state, the service can verify to which service the code belongs.
Assign service to a user
If you take a look at the OpenAPI specification, you can see that there is no endpoint that accepts data. Adding a user is done by the redirect_uri' resource in the OAuth2 workflow, which must point to the
/redirect’ endpoint. The user is then forwarded directly to the RDS and receives feedback on success or failure. Whether the request is valid or not is also determined by the content of the `state’ argument (a JWT object), since it contains information about the request, which is validated by the signature.
OpenAPI
TokenService
lib.User
User
User(self, username:str)
Represents a user, which can access services via tokens.
to_json
User.to_json(self)
Returns this object as a json string.
to_dict
User.to_dict(self)
Returns this object as a dict.
from_json
User.from_json(user:str)
Returns an user object from a json string.
from_dict
User.from_dict(userDict:dict)
Returns an user object from a dict.
lib.Token
Token
Token(self, servicename:str, access_token:str)
This token represents a simple password.
to_json
Token.to_json(self)
Returns this object as a json string.
to_dict
Token.to_dict(self)
Returns this object as a dict.
from_json
Token.from_json(tokenStr:str)
Returns a token object from a json string.
from_dict
Token.from_dict(tokenDict:dict)
Returns a token object from a dict.
OAuth2Token
OAuth2Token(self, servicename:str, access_token:str, refresh_token:str='', expiration_date:datetime.datetime=None)
Represents a token object.
from_token
OAuth2Token.from_token(token:lib.Token.Token, refresh_token:str='', expiration_date:datetime.datetime=None)
Convert the given Token into an oauth2token.
to_json
OAuth2Token.to_json(self)
Returns this object as a json string.
to_dict
OAuth2Token.to_dict(self)
Returns this object as a dict.
from_json
OAuth2Token.from_json(tokenStr:str)
Returns an oauthtoken object from a json string.
from_dict
OAuth2Token.from_dict(tokenDict:dict)
Returns an oauthtoken object from dict.
lib.Service
Service
Service(self, servicename:str)
Represents a service, which can be used in RDS. This service only allows username:password authentication.
to_json
Service.to_json(self)
Returns this object as a json string.
to_dict
Service.to_dict(self)
Returns this object as a dict.
from_json
Service.from_json(serviceStr:str)
Returns an service object from a json string.
from_dict
Service.from_dict(serviceDict:dict)
Returns an service object from a dict string.
OAuth2Service
OAuth2Service(self, servicename:str, authorize_url:str, refresh_url:str, client_id:str, client_secret:str)
Represents an OAuth2 service, which can be used in RDS. This service enables the oauth2 workflow.
refresh
OAuth2Service.refresh(self, token:lib.Token.OAuth2Token)
Refresh the given oauth2 token for specified user.
from_service
OAuth2Service.from_service(service:lib.Service.Service, authorize_url:str, refresh_url:str, client_id:str, client_secret:str)
Converts the given Service to an oauth2service.
to_json
OAuth2Service.to_json(self)
Returns this object as a json string.
to_dict
OAuth2Service.to_dict(self)
Returns this object as a dict.
from_json
OAuth2Service.from_json(serviceStr:str)
Returns an oauthservice object from a json string.
from_dict
OAuth2Service.from_dict(serviceDict:dict)
Returns an oauthservice object from a dict.
lib.TokenService
TokenService
TokenService(self, address=None)
secret
str(object=’') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.str() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to ‘strict’.
getOAuthURIForService
TokenService.getOAuthURIForService(self, service:lib.Service.Service) -> str
Returns authorize-url as String
for the given service.
getAllOAuthURIForService
TokenService.getAllOAuthURIForService(self) -> list
Returns a list
of String
which represents all authorize-urls for registered services.
getService
TokenService.getService(self, servicename:str) -> lib.Service.Service
Returns a dict like self.getAllServices, but for only a single servicename (str).
getAllServices
TokenService.getAllServices(self) -> list
Returns a list
of dict
which represents all registered services.
dict
use struct:
{
“jwt”: string (json / jwt)
}
jwt is base64 encoded, separated by dots, payload struct: { “servicename” “authorize_url” “date” }
internal_getDictWithStateFromService
TokenService.internal_getDictWithStateFromService(self, service:lib.Service.Service) -> dict
Internal use only
Returns a service as jwt encoded dict.
getAllServicesForUser
TokenService.getAllServicesForUser(self, user:lib.User.User) -> list
Returns a list
for all services which the user has registered a token for.
removeService
TokenService.removeService(self, service:lib.Service.Service) -> bool
Remove a registered service.
Returns True
for success.
Raise a ServiceNotFoundError
, if service was not found.
Notice: This function is currently discussed for removal.
addUser
TokenService.addUser(self, user:lib.User.User) -> bool
Adds the given user to the token storage.
Returns True
for success.
Raise an UserAlreadyRegisteredError
, if user already registered.
removeUser
TokenService.removeUser(self, user:lib.User.User) -> bool
Remove the given user from the token storage.
Returns True
for success.
Raise an UserNotfoundError
, if user was not found.
addTokenToUser
TokenService.addTokenToUser(self, token:lib.Token.Token, user:lib.User.User) -> bool
Adds the given token to user.
Returns True
for success.
Raise an UserNotFoundError
, if user not found.
Raise a ServiceNotFoundError
, if service not found.
removeTokenFromUser
TokenService.removeTokenFromUser(self, token:lib.Token.Token, user:lib.User.User) -> bool
Removes given token from user.
Returns True
for success.
Raise an UserNotFoundError
, if user not found.
Raise an TokenNotFoundError
, if token not found for user.
getTokenForServiceFromUser
TokenService.getTokenForServiceFromUser(self, service:lib.Service.Service, user:lib.User.User) -> bool
Returns the token from type Token (struct: servicename: str, access_token: str) for given service from given user.
Raise ServiceNotExistsError, if no token for service was found.
removeTokenForServiceFromUser
TokenService.removeTokenForServiceFromUser(self, service:lib.Service.Service, user:lib.User.User) -> bool
Remove the token for service from user.
Raise ServiceNotFoundError, if no token for service was found.
exchangeAuthCodeToAccessToken
TokenService.exchangeAuthCodeToAccessToken(self, code:str, service:Union[str, lib.Service.OAuth2Service]) -> lib.Token.OAuth2Token
Exchanges the given code
by the given service
lib.Exceptions.ServiceException
ServiceNotFoundError
ServiceNotFoundError(self, service:lib.Service.Service, msg=None)
Represents an error, when a service was not found.
TokenNotFoundError
TokenNotFoundError(self, token:lib.Token.Token, msg=None)
Represents an error, when a token was not found.
UserNotFoundError
UserNotFoundError(self, user:lib.User.User, msg=None)
Represents an error, when an user was not found.
UserHasTokenAlreadyError
UserHasTokenAlreadyError(self, user:lib.User.User, token:lib.Token.Token, msg=None)
Represents an error, when a user has already a token for the service.
UserAlreadyRegisteredError
UserAlreadyRegisteredError(self, user:lib.User.User, msg=None)
Represents an error, when a user-id is already registered.
CodeNotExchangeable
CodeNotExchangeable(self, code, service, msg=None)
Represents an error, when a given code for the oauth workflow could not be exchanged against an access_token.
Util
load_class_from_json
load_class_from_json(jsonStr:str)
Returns the class of the given json string.
load_class_from_dict
load_class_from_dict(data:dict)
Returns the class of the given dict.
initialize_object_from_json
initialize_object_from_json(jsonStr:str)
Initialize and returns an object of the given json string.
This is the easiest way to reverse the to_json method for objects from our lib folder.
initialize_object_from_dict
initialize_object_from_dict(jsonDict:dict)
Initialize and returns an object of the given dict.
This is another easy way to reverse the to_json method for objects from our lib folder.
internal_load_class
internal_load_class(data:dict)
For internal use only.
try_function_on_dict
try_function_on_dict(func:list)
This method trys the given functions on the given dictionary. Returns the first function, which returns a value for given dict.
Main purpose of this is the initialization of multiple Classes from json dicts.
Usage:
func_list = [func1, func2, func3]
x = Util.try_function_on_dict(func_list)
object = x(objDict)
equals to:
try:
try:
func1(objDict)
except:
pass
try:
func2(objDict)
except:
pass
try:
func3(objDict)
except:
pass
except:
raise Exception(...)
Raise an Exception
with all raised exception as strings, if no function returns a value for the given jsonDict.