|
30 | 30 | __all__ = [
|
31 | 31 | "panda_auth_clean",
|
32 | 32 | "panda_auth_expiration",
|
| 33 | + "panda_auth_refresh", |
33 | 34 | "panda_auth_setup",
|
34 | 35 | "panda_auth_status",
|
35 | 36 | "panda_auth_update",
|
36 | 37 | ]
|
37 | 38 |
|
38 | 39 |
|
| 40 | +import base64 |
| 41 | +import json |
39 | 42 | import logging
|
40 | 43 | import os
|
| 44 | +from datetime import datetime, timedelta |
41 | 45 |
|
42 | 46 | import idds.common.utils as idds_utils
|
43 | 47 | import pandaclient.idds_api
|
@@ -151,3 +155,65 @@ def panda_auth_update(idds_server=None, reset=False):
|
151 | 155 | # idds server given. So for now, check result string for keywords.
|
152 | 156 | if "request_id" not in ret[1][-1] or "status" not in ret[1][-1]:
|
153 | 157 | raise RuntimeError(f"Error contacting PanDA service: {ret}")
|
| 158 | + |
| 159 | + |
| 160 | +def panda_auth_refresh(days=4, verbose=False): |
| 161 | + """Refresh auth token""" |
| 162 | + panda_url = os.environ.get("PANDA_URL") |
| 163 | + panda_auth_vo = os.environ.get("PANDA_AUTH_VO") |
| 164 | + url_prefix = panda_url.split("/server", 1)[0] |
| 165 | + auth_url = f"{url_prefix}/auth/{panda_auth_vo}_auth_config.json" |
| 166 | + open_id = OpenIdConnect_Utils(auth_url, log_stream=_LOG, verbose=verbose) |
| 167 | + |
| 168 | + token_file = open_id.get_token_path() |
| 169 | + if os.path.exists(token_file): |
| 170 | + with open(token_file) as f: |
| 171 | + data = json.load(f) |
| 172 | + enc = data["id_token"].split(".")[1] |
| 173 | + enc += "=" * (-len(enc) % 4) |
| 174 | + dec = json.loads(base64.urlsafe_b64decode(enc.encode())) |
| 175 | + exp_time = datetime.utcfromtimestamp(dec["exp"]) |
| 176 | + delta = exp_time - datetime.utcnow() |
| 177 | + minutes = delta.total_seconds() / 60 |
| 178 | + print(f"Token will expire in {minutes} minutes.") |
| 179 | + print(f"Token expiration time : {exp_time.strftime('%Y-%m-%d %H:%M:%S')} UTC") |
| 180 | + if delta < timedelta(minutes=0): |
| 181 | + print("Token already expired. Cannot refresh.") |
| 182 | + return |
| 183 | + elif delta > timedelta(days=days): |
| 184 | + print("\n" + "=" * 60) |
| 185 | + print(f" Too early to refresh. More than {days} day(s) until expiration.") |
| 186 | + print(" To change this threshold, use the --days option:") |
| 187 | + print(" Example: panda_auth refresh --days 10") |
| 188 | + print("=" * 60 + "\n") |
| 189 | + return |
| 190 | + else: |
| 191 | + print("Cannot find token file.") |
| 192 | + return |
| 193 | + refresh_token_string = data["refresh_token"] |
| 194 | + |
| 195 | + s, auth_config = open_id.fetch_page(open_id.auth_config_url) |
| 196 | + if not s: |
| 197 | + print("Failed to get Auth configuration") |
| 198 | + return |
| 199 | + |
| 200 | + s, endpoint_config = open_id.fetch_page(auth_config["oidc_config_url"]) |
| 201 | + if not s: |
| 202 | + print("Failed to get endpoint configuration") |
| 203 | + return |
| 204 | + |
| 205 | + s, o = open_id.refresh_token( |
| 206 | + endpoint_config["token_endpoint"], |
| 207 | + auth_config["client_id"], |
| 208 | + auth_config["client_secret"], |
| 209 | + refresh_token_string, |
| 210 | + ) |
| 211 | + |
| 212 | + if not s: |
| 213 | + print("Failed to refresh token") |
| 214 | + return |
| 215 | + else: |
| 216 | + status = panda_auth_status() |
| 217 | + if status: |
| 218 | + print(f"{'New expiration time:':23} {datetime.utcfromtimestamp(status['exp'])} UTC") |
| 219 | + print("Success to refresh token") |
0 commit comments