diff --git a/README.md b/README.md index 5bbb132..8ad4164 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,20 @@ stateless_incident = Incident( ) ``` + +### Get a new authentication token + +If your argus server is running version 1.29.0 or newer you can request to get +a new token (with a new expiration date) via API version 2. The token you are +using to access the server with must still be valid. + +```python +tokenobj = c.refresh_token() +c = Client(api_root_url="https://argus.example.org/api/v2", token=tokenobj.token) +# save the contents of tokenobj in an environment variable, config file or +# secrets file so that it is not lost on program exit +``` + ## BUGS * Doesn't provide high-level error handling yet. diff --git a/src/pyargus/api.py b/src/pyargus/api.py index 9f829a6..b829a02 100644 --- a/src/pyargus/api.py +++ b/src/pyargus/api.py @@ -21,6 +21,7 @@ def connect(api_root_url: str, token: str, timeout: float = 2.0) -> API: argusapi.add_resource( resource_name="acknowledgements", resource_class=IncidentAcknowledgementResource ) + argusapi.add_resource(resource_name="tokens", resource_class=ExpiringTokenResource) return argusapi @@ -51,3 +52,9 @@ class IncidentAcknowledgementResource(Resource): "create": {"method": "POST", "url": "incidents/{}/acks"}, "retrieve": {"method": "GET", "url": "incidents/{}/acks/{}"}, } + + +class ExpiringTokenResource(Resource): + actions = { + "refresh": {"method": "POST", "url": "auth/token/login/"}, + } diff --git a/src/pyargus/client.py b/src/pyargus/client.py index becc005..c5dc414 100644 --- a/src/pyargus/client.py +++ b/src/pyargus/client.py @@ -131,6 +131,19 @@ def post_incident_event(self, incident: IncidentType, event: models.Event): response = self.api.events.create(incident_pk, body=body) return models.Event.from_json(response.body) + def refresh_token(self) -> models.ExpiringToken: + """Post w/o body to get a new token and its expiration timestamp + + It will be necessary to re-initialize the client as the old token has + been rendered invalid. + + Store the new token (and the returned expiration datetime) where your + program can load it on next run: environment variable, config file or + secrets file. + """ + response = self.api.tokens.refresh() + return models.ExpiringToken.from_json(response.body) + def paginated_query(method: Callable, *args, **kwargs) -> Iterator[Tuple]: """Extracts paginated results from a simple_rest_client API call. diff --git a/src/pyargus/models.py b/src/pyargus/models.py index 2cd53a9..14ba25e 100644 --- a/src/pyargus/models.py +++ b/src/pyargus/models.py @@ -164,3 +164,19 @@ def from_json(cls, data: dict) -> Acknowledgement: else None, } return cls(**kwargs) + + +@dataclass +class ExpiringToken: + """Class for describing the authentication token""" + + expiration: datetime + token: int + + @classmethod + def from_json(cls, data: dict) -> ExpiringToken: + kwargs = { + "expiration": parse_date(data["expiration"]), + "token": parse_date(data["token"]), + } + return cls(**kwargs)