Skip to content

Commit

Permalink
Merge pull request #216 from cho4036/develop
Browse files Browse the repository at this point in the history
improve: add an API to verify token & improve an old verification logic
  • Loading branch information
ktkfree authored Jan 17, 2024
2 parents 9423ea3 + 11a79f9 commit c2abbe9
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 36 deletions.
31 changes: 31 additions & 0 deletions internal/delivery/http/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type IAuthHandler interface {
VerifyIdentityForLostId(w http.ResponseWriter, r *http.Request)
VerifyIdentityForLostPassword(w http.ResponseWriter, r *http.Request)

VerifyToken(w http.ResponseWriter, r *http.Request)
//Authenticate(next http.Handler) http.Handler
}
type AuthHandler struct {
Expand Down Expand Up @@ -284,3 +285,33 @@ func (h *AuthHandler) PingToken(w http.ResponseWriter, r *http.Request) {

ResponseJSON(w, r, http.StatusOK, nil)
}

// VerifyToken godoc
// @Tags Auth
// @Summary verify token
// @Description verify token
// @Success 200 {object} nil
// @Router /auth/verify-token [get]

func (h *AuthHandler) VerifyToken(w http.ResponseWriter, r *http.Request) {
token, ok := request.TokenFrom(r.Context())
if !ok {
log.ErrorfWithContext(r.Context(), "token is not found")
ErrorJSON(w, r, httpErrors.NewInternalServerError(fmt.Errorf("token is not found"), "C_INTERNAL_ERROR", ""))
return
}

isActive, err := h.usecase.VerifyToken(token)
if err != nil {
log.ErrorfWithContext(r.Context(), "error is :%s(%T)", err.Error(), err)
ErrorJSON(w, r, httpErrors.NewInternalServerError(err, "", ""))
return
}

if !isActive {
ErrorJSON(w, r, httpErrors.NewUnauthorizedError(fmt.Errorf("token is not active"), "C_UNAUTHORIZED", ""))
return
}

ResponseJSON(w, r, http.StatusOK, nil)
}
12 changes: 6 additions & 6 deletions internal/keycloak/keycloak.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ type IKeycloak interface {
JoinGroup(organizationId string, userId string, groupName string) error
LeaveGroup(organizationId string, userId string, groupName string) error

VerifyAccessToken(token string, organizationId string) error
VerifyAccessToken(token string, organizationId string) (bool, error)
GetSessions(userId string, organizationId string) (*[]string, error)
}
type Keycloak struct {
Expand Down Expand Up @@ -364,17 +364,17 @@ func (k *Keycloak) DeleteUser(organizationId string, userAccountId string) error
return nil
}

func (k *Keycloak) VerifyAccessToken(token string, organizationId string) error {
func (k *Keycloak) VerifyAccessToken(token string, organizationId string) (bool, error) {
ctx := context.Background()
rptResult, err := k.client.RetrospectToken(ctx, token, DefaultClientID, k.config.ClientSecret, organizationId)
if err != nil {
return err
return false, err
}

if !(*rptResult.Active) {
return err
return false, nil
}
return nil

return true, nil
}

func (k *Keycloak) GetSessions(userId string, organizationId string) (*[]string, error) {
Expand Down
34 changes: 5 additions & 29 deletions internal/middleware/auth/authenticator/keycloak/keycloak.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,23 +53,19 @@ func (a *keycloakAuthenticator) AuthenticateToken(r *http.Request, token string)
return nil, false, err
}

if parsedToken.Method.Alg() != "RS256" {
return nil, false, fmt.Errorf("invalid token")
}

if parsedToken.Claims.Valid() != nil {
return nil, false, fmt.Errorf("invalid token")
}

organizationId, ok := parsedToken.Claims.(jwtWithouKey.MapClaims)["organization"].(string)
if !ok {
return nil, false, fmt.Errorf("organization is not found in token")
}

if err := a.kc.VerifyAccessToken(token, organizationId); err != nil {
isActive, err := a.kc.VerifyAccessToken(token, organizationId)
if err != nil {
log.Errorf("failed to verify access token: %v", err)
return nil, false, err
}
if !isActive {
return nil, false, fmt.Errorf("token is not active")
}

roleProjectMapping := make(map[string]string)
for _, role := range parsedToken.Claims.(jwtWithouKey.MapClaims)["tks-role"].([]interface{}) {
Expand All @@ -93,26 +89,6 @@ func (a *keycloakAuthenticator) AuthenticateToken(r *http.Request, token string)
return nil, false, fmt.Errorf("session id is not found in token")
}

sessionIds, err := a.kc.GetSessions(userId.String(), organizationId)
if err != nil {
log.Errorf("failed to get sessions: %v", err)

return nil, false, err
}
if len(*sessionIds) == 0 {
return nil, false, fmt.Errorf("invalid session")
}
var matched bool = false
for _, id := range *sessionIds {
if id == requestSessionId {
matched = true
break
}
}
if !matched {
return nil, false, fmt.Errorf("invalid session")
}

userInfo := &user.DefaultInfo{
UserId: userId,
OrganizationId: organizationId,
Expand Down
1 change: 1 addition & 0 deletions internal/route/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ func SetupRouter(db *gorm.DB, argoClient argowf.ArgoClient, kc keycloak.IKeycloa
r.HandleFunc(API_PREFIX+API_VERSION+"/auth/find-password/verification", authHandler.FindPassword).Methods(http.MethodPost)
r.HandleFunc(API_PREFIX+API_VERSION+"/auth/find-id/code", authHandler.VerifyIdentityForLostId).Methods(http.MethodPost)
r.HandleFunc(API_PREFIX+API_VERSION+"/auth/find-password/code", authHandler.VerifyIdentityForLostPassword).Methods(http.MethodPost)
r.HandleFunc(API_PREFIX+API_VERSION+"/auth/verify-token", authHandler.VerifyToken).Methods(http.MethodGet)
//r.HandleFunc(API_PREFIX+API_VERSION+"/cookie-test", authHandler.CookieTest).Methods(http.MethodPost)
//r.HandleFunc(API_PREFIX+API_VERSION+"/auth/callback", authHandler.CookieTestCallback).Methods(http.MethodGet)

Expand Down
29 changes: 28 additions & 1 deletion internal/usecase/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type IAuthUsecase interface {
FetchRoles() (out []domain.Role, err error)
SingleSignIn(organizationId, accountId, password string) ([]*http.Cookie, error)
SingleSignOut(organizationId string) (string, []*http.Cookie, error)
VerifyToken(token string) (bool, error)
}

const (
Expand Down Expand Up @@ -121,10 +122,14 @@ func (u *AuthUsecase) PingToken(accessToken string, organizationId string) error
return fmt.Errorf("invalid token")
}

if err := u.kc.VerifyAccessToken(accessToken, organizationId); err != nil {
isActive, err := u.kc.VerifyAccessToken(accessToken, organizationId)
if err != nil {
log.Errorf("failed to verify access token: %v", err)
return err
}
if !isActive {
return fmt.Errorf("token is not active")
}

userId, err := uuid.Parse(parsedToken.Claims.(jwtWithouKey.MapClaims)["sub"].(string))
if err != nil {
Expand Down Expand Up @@ -381,6 +386,28 @@ func (u *AuthUsecase) SingleSignOut(organizationId string) (string, []*http.Cook
return redirectUrl, cookies, nil
}

func (u *AuthUsecase) VerifyToken(token string) (bool, error) {
parsedToken, _, err := new(jwtWithouKey.Parser).ParseUnverified(token, jwtWithouKey.MapClaims{})
if err != nil {
return false, err
}
org, ok := parsedToken.Claims.(jwtWithouKey.MapClaims)["organization"].(string)
if !ok {
return false, fmt.Errorf("organization is not found in token")
}

isActive, err := u.kc.VerifyAccessToken(token, org)
if err != nil {
log.Errorf("failed to verify access token: %v", err)
return false, err
}
if !isActive {
return false, fmt.Errorf("token is not active")
}

return true, nil
}

func (u *AuthUsecase) isExpiredEmailCode(code repository.CacheEmailCode) bool {
return !helper.IsDurationExpired(code.UpdatedAt, internal.EmailCodeExpireTime)
}
Expand Down

0 comments on commit c2abbe9

Please sign in to comment.