Skip to content

Commit

Permalink
Merge pull request #45 from cho4036/develop
Browse files Browse the repository at this point in the history
관리자의 user password 초기화 기능 추가 및 다음에 변경하기 기능 추가
  • Loading branch information
ktkfree authored Apr 27, 2023
2 parents 66413a0 + dfa6426 commit ff4fba4
Show file tree
Hide file tree
Showing 10 changed files with 397 additions and 5 deletions.
81 changes: 81 additions & 0 deletions api/swagger/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -1854,6 +1854,46 @@ const docTemplate = `{
}
}
},
"/organizations/{organizationId}/my-profile/next-password-change": {
"put": {
"security": [
{
"JWT": []
}
],
"description": "Update user's password expired date to current date",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"My-profile"
],
"summary": "Update user's password expired date to current date",
"parameters": [
{
"type": "string",
"description": "organizationId",
"name": "organizationId",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK"
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/httpErrors.RestError"
}
}
}
}
},
"/organizations/{organizationId}/my-profile/password": {
"put": {
"security": [
Expand Down Expand Up @@ -2503,6 +2543,47 @@ const docTemplate = `{
}
}
},
"/organizations/{organizationId}/users/{accountId}/reset-password": {
"put": {
"security": [
{
"JWT": []
}
],
"description": "Reset user's password as temporary password by admin and send email to user",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Users"
],
"summary": "Reset user's password as temporary password by admin",
"parameters": [
{
"type": "string",
"description": "organizationId",
"name": "organizationId",
"in": "path",
"required": true
},
{
"type": "string",
"description": "accountId",
"name": "accountId",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/stack-templates": {
"get": {
"security": [
Expand Down
81 changes: 81 additions & 0 deletions api/swagger/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -1847,6 +1847,46 @@
}
}
},
"/organizations/{organizationId}/my-profile/next-password-change": {
"put": {
"security": [
{
"JWT": []
}
],
"description": "Update user's password expired date to current date",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"My-profile"
],
"summary": "Update user's password expired date to current date",
"parameters": [
{
"type": "string",
"description": "organizationId",
"name": "organizationId",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK"
},
"400": {
"description": "Bad Request",
"schema": {
"$ref": "#/definitions/httpErrors.RestError"
}
}
}
}
},
"/organizations/{organizationId}/my-profile/password": {
"put": {
"security": [
Expand Down Expand Up @@ -2496,6 +2536,47 @@
}
}
},
"/organizations/{organizationId}/users/{accountId}/reset-password": {
"put": {
"security": [
{
"JWT": []
}
],
"description": "Reset user's password as temporary password by admin and send email to user",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"Users"
],
"summary": "Reset user's password as temporary password by admin",
"parameters": [
{
"type": "string",
"description": "organizationId",
"name": "organizationId",
"in": "path",
"required": true
},
{
"type": "string",
"description": "accountId",
"name": "accountId",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK"
}
}
}
},
"/stack-templates": {
"get": {
"security": [
Expand Down
52 changes: 52 additions & 0 deletions api/swagger/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2693,6 +2693,31 @@ paths:
summary: Update my profile detail
tags:
- My-profile
/organizations/{organizationId}/my-profile/next-password-change:
put:
consumes:
- application/json
description: Update user's password expired date to current date
parameters:
- description: organizationId
in: path
name: organizationId
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
"400":
description: Bad Request
schema:
$ref: '#/definitions/httpErrors.RestError'
security:
- JWT: []
summary: Update user's password expired date to current date
tags:
- My-profile
/organizations/{organizationId}/my-profile/password:
put:
consumes:
Expand Down Expand Up @@ -3054,6 +3079,33 @@ paths:
summary: Update user
tags:
- Users
/organizations/{organizationId}/users/{accountId}/reset-password:
put:
consumes:
- application/json
description: Reset user's password as temporary password by admin and send email
to user
parameters:
- description: organizationId
in: path
name: organizationId
required: true
type: string
- description: accountId
in: path
name: accountId
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
security:
- JWT: []
summary: Reset user's password as temporary password by admin
tags:
- Users
/organizations/{organizationId}/users/accountId/{accountId}/existence:
get:
description: return true when accountId exists
Expand Down
6 changes: 4 additions & 2 deletions internal/aws/ses/ses.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,10 @@ func SendEmailForVerityIdentity(client *awsSes.Client, targetEmailAddress string

func SendEmailForTemporaryPassword(client *awsSes.Client, targetEmailAddress string, randomPassword string) error {
subject := "[TKS] 비밀번호 초기화"
body := "임시 비밀번호가 발급되었습니다.\n\n" + "임시 비밀번호는 [" + randomPassword + "]이며\n" +
"로그인 후 비밀번호를 변경하여 사용하십시요.\n\n" + "TKS를 이용해 주셔서 감사합니다.\nTKS Team 드림"
body := "임시 비밀번호가 발급되었습니다.\n" +
"로그인 후 비밀번호를 변경하여 사용하십시오.\n\n" +
"임시 비밀번호: " + randomPassword + "\n\n" +
"TKS를 이용해 주셔서 감사합니다.\nTKS Team 드림"

input := &awsSes.SendEmailInput{
Destination: &types.Destination{
Expand Down
62 changes: 62 additions & 0 deletions internal/delivery/http/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ type IUserHandler interface {
Get(w http.ResponseWriter, r *http.Request)
Delete(w http.ResponseWriter, r *http.Request)
Update(w http.ResponseWriter, r *http.Request)
ResetPassword(w http.ResponseWriter, r *http.Request)

GetMyProfile(w http.ResponseWriter, r *http.Request)
UpdateMyProfile(w http.ResponseWriter, r *http.Request)
UpdateMyPassword(w http.ResponseWriter, r *http.Request)
RenewPasswordExpiredDate(w http.ResponseWriter, r *http.Request)
DeleteMyProfile(w http.ResponseWriter, r *http.Request)

CheckId(w http.ResponseWriter, r *http.Request)
Expand Down Expand Up @@ -294,6 +296,39 @@ func (u UserHandler) Update(w http.ResponseWriter, r *http.Request) {
ResponseJSON(w, http.StatusOK, out)
}

// ResetPassword godoc
// @Tags Users
// @Summary Reset user's password as temporary password by admin
// @Description Reset user's password as temporary password by admin and send email to user
// @Accept json
// @Produce json
// @Param organizationId path string true "organizationId"
// @Param accountId path string true "accountId"
// @Success 200
// @Router /organizations/{organizationId}/users/{accountId}/reset-password [put]
// @Security JWT
func (u UserHandler) ResetPassword(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
accountId, ok := vars["accountId"]
if !ok {
ErrorJSON(w, httpErrors.NewBadRequestError(fmt.Errorf("accountId not found in path")))
return
}
organizationId, ok := vars["organizationId"]
if !ok {
ErrorJSON(w, httpErrors.NewBadRequestError(fmt.Errorf("organizationId not found in path")))
return
}

err := u.usecase.ResetPasswordByAccountId(accountId, organizationId)
if err != nil {
ErrorJSON(w, err)
return
}

ResponseJSON(w, http.StatusOK, nil)
}

// GetMyProfile godoc
// @Tags My-profile
// @Summary Get my profile detail
Expand Down Expand Up @@ -436,6 +471,33 @@ func (u UserHandler) UpdateMyPassword(w http.ResponseWriter, r *http.Request) {
ResponseJSON(w, http.StatusOK, nil)
}

// RenewPasswordExpiredDate godoc
// @Tags My-profile
// @Summary Update user's password expired date to current date
// @Description Update user's password expired date to current date
// @Accept json
// @Produce json
// @Param organizationId path string true "organizationId"
// @Success 200
// @Failure 400 {object} httpErrors.RestError
// @Router /organizations/{organizationId}/my-profile/next-password-change [put]
// @Security JWT
func (u UserHandler) RenewPasswordExpiredDate(w http.ResponseWriter, r *http.Request) {
requestUserInfo, ok := request.UserFrom(r.Context())
if !ok {
ErrorJSON(w, httpErrors.NewInternalServerError(fmt.Errorf("user not found in request")))
return
}

err := u.usecase.RenewalPasswordExpiredTime(r.Context(), requestUserInfo.GetUserId())
if err != nil {
ErrorJSON(w, err)
return
}

ResponseJSON(w, http.StatusOK, nil)
}

// DeleteMyProfile godoc
// @Tags My-profile
// @Summary Delete myProfile
Expand Down
2 changes: 1 addition & 1 deletion internal/keycloak/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ const (
DefaultClientSecret = "secret"
AdminCliClientID = "admin-cli"
accessTokenLifespan = 60 * 60 * 24 // 1 day
ssoSessionIdleTimeout = 60 * 60 * 8 // 2 hours
ssoSessionIdleTimeout = 60 * 60 * 8 // 8 hours
ssoSessionMaxLifespan = 60 * 60 * 24 // 1 day
)
16 changes: 14 additions & 2 deletions internal/middleware/auth/authorizer/password.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,24 @@ func PasswordFilter(handler http.Handler, repo repository.Repository) http.Handl
return
}
if helper.IsDurationExpired(storedUser.PasswordUpdatedAt, internal.PasswordExpiredDuration) {
allowedUrl := internal.API_PREFIX + internal.API_VERSION + "/organizations/" + requestUserInfo.GetOrganizationId() + "/my-profile" + "/password"
if !(r.URL.Path == allowedUrl && r.Method == http.MethodPut) {
allowedUrl := [2]string{
internal.API_PREFIX + internal.API_VERSION + "/organizations/" + requestUserInfo.GetOrganizationId() + "/my-profile" + "/password",
internal.API_PREFIX + internal.API_VERSION + "/organizations/" + requestUserInfo.GetOrganizationId() + "/my-profile" + "/next-password-change",
}
if !(urlContains(allowedUrl, r.URL.Path) && r.Method == http.MethodPut) {
internalHttp.ErrorJSON(w, httpErrors.NewForbiddenError(fmt.Errorf("password expired")))
return
}
}
handler.ServeHTTP(w, r)
})
}

func urlContains(urls [2]string, url string) bool {
for _, u := range urls {
if u == url {
return true
}
}
return false
}
Loading

0 comments on commit ff4fba4

Please sign in to comment.