Skip to content

Commit 3968e9f

Browse files
committed
feat: add new feature for setting refresh timeout for domain admin user
Signed-off-by: ImMin5 <mino@megazone.com>
1 parent 00a5efc commit 3968e9f

8 files changed

Lines changed: 93 additions & 15 deletions

File tree

‎src/spaceone/identity/conf/global_conf.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
"token_timeout": 1800, # 30 minutes
5555
"token_max_timeout": 604800, # 7 days
5656
"refresh_timeout": 10800, # 3 hours
57+
"admin_refresh_timeout": 2592000, # 30days
5758
},
5859
"mfa": {"verify_code_timeout": 300},
5960
}

‎src/spaceone/identity/interface/grpc/user_profile.py‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from google.protobuf.json_format import ParseDict
2-
from spaceone.api.identity.v2 import (user_pb2, user_profile_pb2,
3-
user_profile_pb2_grpc)
2+
from spaceone.api.identity.v2 import user_pb2, user_profile_pb2, user_profile_pb2_grpc
43
from spaceone.core.pygrpc import BaseAPI
54

65
from spaceone.identity.service.user_profile_service import UserProfileService
@@ -16,6 +15,12 @@ def update(self, request, context):
1615
response: dict = user_profile_svc.update(params)
1716
return ParseDict(response, user_pb2.UserInfo())
1817

18+
def set_refresh_timeout(self, request, context):
19+
params, metadata = self.parse_request(request, context)
20+
user_profile_svc = UserProfileService(metadata)
21+
response: dict = user_profile_svc.set_refresh_timeout(params)
22+
return ParseDict(response, user_pb2.UserInfo())
23+
1924
def verify_email(self, request, context):
2025
params, metadata = self.parse_request(request, context)
2126
user_profile_svc = UserProfileService(metadata)

‎src/spaceone/identity/manager/token_manager/base.py‎

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,15 @@ def get_token_manager_by_auth_type(cls, auth_type):
3939
raise ERROR_INVALID_AUTHENTICATION_TYPE(auth_type=auth_type)
4040

4141
def issue_token(
42-
self,
43-
private_jwk,
44-
refresh_private_jwk,
45-
domain_id,
46-
workspace_id=None,
47-
timeout=None,
48-
permissions=None,
49-
projects=None,
50-
app_id=None,
42+
self,
43+
private_jwk,
44+
refresh_private_jwk,
45+
domain_id,
46+
workspace_id=None,
47+
timeout=None,
48+
permissions=None,
49+
projects=None,
50+
app_id=None,
5151
):
5252
if self.is_authenticated is False:
5353
raise ERROR_NOT_AUTHENTICATED()
@@ -80,7 +80,7 @@ def issue_token(
8080
)
8181

8282
refresh_token = key_gen.generate_token(
83-
"REFRESH_TOKEN", timeout=self.CONST_REFRESH_TIMEOUT
83+
"REFRESH_TOKEN", timeout=self._get_refresh_token_timeout()
8484
)
8585
if self.owner_type != "SYSTEM":
8686
# todo: remove
@@ -89,7 +89,7 @@ def issue_token(
8989
return {"access_token": access_token, "refresh_token": refresh_token}
9090

9191
def issue_temporary_token(
92-
self, user_id: str, domain_id: str, private_jwk, timeout: int
92+
self, user_id: str, domain_id: str, private_jwk: dict, timeout: int
9393
) -> dict:
9494
permissions = [
9595
"identity:UserProfile",
@@ -127,6 +127,17 @@ def set_timeout(self, timeout: Union[int, None]) -> int:
127127
timeout = self.CONST_TOKEN_TIMEOUT
128128
return timeout
129129

130+
def _get_refresh_token_timeout(self) -> int:
131+
refresh_timeout = self.CONST_REFRESH_TIMEOUT
132+
if (
133+
self.user
134+
and self.user.role_type == "DOMAIN_ADMIN"
135+
and self.user.refresh_timeout
136+
):
137+
refresh_timeout = max(self.user.refresh_timeout, refresh_timeout)
138+
139+
return refresh_timeout
140+
130141
@staticmethod
131142
def check_verify_code(user_id, domain_id, verify_code):
132143
if cache.is_set():

‎src/spaceone/identity/model/user/database.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ class User(MongoModel):
3636
required_actions = ListField(StringField(choices=("UPDATE_PASSWORD",)), default=[])
3737
language = StringField(max_length=7, default="en")
3838
timezone = StringField(max_length=50, default="UTC")
39-
tags = DictField(Default=None)
39+
refresh_timeout = IntField(default=None, min_value=1800, max_value=2592000)
40+
tags = DictField(default=None)
4041
domain_id = StringField(max_length=40)
4142
created_at = DateTimeField(auto_now_add=True)
4243
last_accessed_at = DateTimeField(default=None, null=True)
@@ -54,6 +55,7 @@ class User(MongoModel):
5455
"language",
5556
"timezone",
5657
"required_actions",
58+
"refresh_timeout",
5759
"tags",
5860
"last_accessed_at",
5961
],

‎src/spaceone/identity/model/user/response.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class UserResponse(BaseModel):
2727
language: Union[str, None] = None
2828
timezone: Union[str, None] = None
2929
required_actions: Union[List[str], None] = None
30+
refresh_timeout: Union[int, None] = None
3031
tags: Union[dict, None] = None
3132
domain_id: Union[str, None] = None
3233
created_at: Union[datetime, None] = None

‎src/spaceone/identity/model/user_profile/request.py‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
__all__ = [
66
"UserProfileUpdateRequest",
7+
"UserProfileSetRefreshTokenTimeout",
78
"UserProfileVerifyEmailRequest",
89
"UserProfileConfirmEmailRequest",
910
"UserProfileResetPasswordRequest",
@@ -27,6 +28,12 @@ class UserProfileUpdateRequest(BaseModel):
2728
domain_id: str
2829

2930

31+
class UserProfileSetRefreshTokenTimeout(BaseModel):
32+
user_id: str
33+
refresh_timeout: int
34+
domain_id: str
35+
36+
3037
class UserProfileVerifyEmailRequest(BaseModel):
3138
user_id: str
3239
email: Union[str, None] = None

‎src/spaceone/identity/service/user_profile_service.py‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,38 @@ def update(self, params: UserProfileUpdateRequest) -> Union[UserResponse, dict]:
8282

8383
return UserResponse(**user_vo.to_dict())
8484

85+
@transaction(permission="identity:UserProfile.write", role_types=["USER"])
86+
@convert_model
87+
def set_refresh_timeout(
88+
self, params: UserProfileSetRefreshTokenTimeout
89+
) -> Union[UserResponse, dict]:
90+
"""
91+
Args:
92+
params (UserProfileSetRefreshTokenTimeout): {
93+
"refresh_timeout": "int",
94+
"user_id": "str", # inject from auth
95+
"domain_id": "str" # inject from auth
96+
}
97+
Returns:
98+
UserResponse:
99+
"""
100+
101+
user_id = params.user_id
102+
domain_id = params.domain_id
103+
user_vo = self.user_mgr.get_user(user_id, domain_id)
104+
105+
if user_vo.role_type != "DOMAIN_ADMIN":
106+
raise ERROR_PERMISSION_DENIED()
107+
108+
refresh_timeout = self._get_refresh_timeout_from_config(params.refresh_timeout)
109+
print(refresh_timeout)
110+
user_vo = self.user_mgr.update_user_by_vo(
111+
{"refresh_timeout": refresh_timeout}, user_vo
112+
)
113+
114+
print(user_vo.refresh_timeout)
115+
return UserResponse(**user_vo.to_dict())
116+
85117
@transaction(permission="identity:UserProfile.write", role_types=["USER"])
86118
@convert_model
87119
def verify_email(self, params: UserProfileVerifyEmailRequest) -> None:
@@ -620,3 +652,20 @@ def _get_my_workspace_groups_info(
620652
def _check_mfa_options(options, mfa_type):
621653
if mfa_type in ["EMAIL"] and not options:
622654
raise ERROR_REQUIRED_PARAMETER(key="options.email")
655+
656+
@staticmethod
657+
def _get_refresh_timeout_from_config(refresh_timeout: int) -> int:
658+
identity_conf = config.get_global("IDENTITY") or {}
659+
token_conf = identity_conf.get("token", {})
660+
config_refresh_timeout = token_conf.get("refresh_timeout")
661+
if refresh_timeout < config_refresh_timeout:
662+
raise ERROR_INVALID_PARAMETER(
663+
key="refresh_timeout",
664+
reason=f"Minimum value for refresh_timeout is {config_refresh_timeout}",
665+
)
666+
refresh_timeout = max(refresh_timeout, config_refresh_timeout)
667+
668+
config_admin_refresh_timeout = token_conf.get("admin_refresh_timeout", 2592000)
669+
refresh_timeout = min(refresh_timeout, config_admin_refresh_timeout)
670+
671+
return refresh_timeout

‎src/spaceone/identity/service/user_service.py‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,9 @@ def disable_mfa(self, params: UserDisableMFARequest) -> Union[UserResponse, dict
254254
if mfa_type == "OTP":
255255
user_secret_id = user_mfa.get("options", {}).get("user_secret_id")
256256
secret_manager: SecretManager = self.locator.get_manager(SecretManager)
257-
secret_manager.delete_user_secret_with_system_token(domain_id, user_secret_id)
257+
secret_manager.delete_user_secret_with_system_token(
258+
domain_id, user_secret_id
259+
)
258260

259261
user_mfa = {"state": "DISABLED"}
260262
self.user_mgr.update_user_by_vo({"mfa": user_mfa}, user_vo)

0 commit comments

Comments
 (0)