2023-05-24 12:16:03 +09:00
|
|
|
package core
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"io"
|
|
|
|
|
"net/http"
|
|
|
|
|
"net/url"
|
|
|
|
|
"time"
|
|
|
|
|
|
2023-05-24 15:31:01 +09:00
|
|
|
"repositories.action2quare.com/ayo/gocommon/logger"
|
2023-05-24 12:16:03 +09:00
|
|
|
|
|
|
|
|
"go.mongodb.org/mongo-driver/bson"
|
|
|
|
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
|
|
|
|
"go.mongodb.org/mongo-driver/mongo/options"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Microsoft_ValidationResponse struct {
|
|
|
|
|
IDToken string `json:"id_token"`
|
|
|
|
|
RefreshToken string `json:"refresh_token"`
|
|
|
|
|
AccessToken string `json:"access_token"`
|
|
|
|
|
TokenType string `json:"token_type"`
|
|
|
|
|
ExpiresIn int `json:"expires_in"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Microsoft_UserInfoResponse struct {
|
|
|
|
|
Sub string `json:"sub"`
|
|
|
|
|
Givenname string `json:"givenname"`
|
|
|
|
|
Familyname string `json:"familyname"`
|
|
|
|
|
Email string `json:"email"`
|
|
|
|
|
Locale string `json:"locale"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (mg *Maingate) platform_microsoft_get_login_url(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
browserinfo, err := mg.GetUserBrowserInfo(r)
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
existid := r.URL.Query().Get("existid")
|
|
|
|
|
//fmt.Println("existid =>", existid)
|
|
|
|
|
if existid != "" {
|
|
|
|
|
//기존 계정이 있는 경우에는 그 계정 부터 조회한다.
|
|
|
|
|
info, err := mg.getUserTokenWithCheck(AuthPlatformMicrosoft, existid, browserinfo)
|
|
|
|
|
if err == nil {
|
|
|
|
|
if info.token != "" {
|
|
|
|
|
params := url.Values{}
|
|
|
|
|
params.Add("id", existid)
|
|
|
|
|
params.Add("authtype", AuthPlatformMicrosoft)
|
|
|
|
|
http.Redirect(w, r, "actionsquare://login?"+params.Encode(), http.StatusSeeOther)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sessionkey := mg.GeneratePlatformLoginNonceKey()
|
|
|
|
|
nonce := mg.GeneratePlatformLoginNonceKey()
|
|
|
|
|
|
|
|
|
|
mg.mongoClient.Delete(CollectionPlatformLoginToken, bson.M{
|
|
|
|
|
"platform": AuthPlatformMicrosoft,
|
|
|
|
|
"key": sessionkey,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
_, _, err = mg.mongoClient.Update(CollectionPlatformLoginToken, bson.M{
|
|
|
|
|
"_id": primitive.NewObjectID(),
|
|
|
|
|
}, bson.M{
|
|
|
|
|
"$setOnInsert": bson.M{
|
|
|
|
|
"platform": AuthPlatformMicrosoft,
|
|
|
|
|
"key": sessionkey,
|
|
|
|
|
"nonce": nonce,
|
|
|
|
|
"brinfo": browserinfo,
|
|
|
|
|
},
|
|
|
|
|
}, options.Update().SetUpsert(true))
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
params := url.Values{}
|
2023-12-06 16:35:55 +09:00
|
|
|
params.Add("client_id", config.MicrosoftClientId)
|
2023-05-24 12:16:03 +09:00
|
|
|
params.Add("response_type", "code")
|
2023-12-06 16:35:55 +09:00
|
|
|
params.Add("redirect_uri", config.RedirectBaseUrl+"/authorize/"+AuthPlatformMicrosoft)
|
2023-05-24 12:16:03 +09:00
|
|
|
params.Add("response_mode", "query")
|
|
|
|
|
params.Add("scope", "openid offline_access https://graph.microsoft.com/mail.read")
|
|
|
|
|
|
|
|
|
|
params.Add("nonce", nonce)
|
|
|
|
|
|
|
|
|
|
// set cookie for storing token
|
|
|
|
|
cookie := http.Cookie{
|
|
|
|
|
Name: "LoginFlowContext_SessionKey",
|
|
|
|
|
Value: sessionkey,
|
|
|
|
|
Expires: time.Now().Add(1 * time.Hour),
|
|
|
|
|
//SameSite: http.SameSiteStrictMode,
|
|
|
|
|
SameSite: http.SameSiteLaxMode,
|
|
|
|
|
// HttpOnly: false,
|
|
|
|
|
Secure: true,
|
|
|
|
|
Path: "/",
|
|
|
|
|
}
|
|
|
|
|
http.SetCookie(w, &cookie)
|
|
|
|
|
|
|
|
|
|
//Set-Cookie
|
|
|
|
|
//fmt.Println(mg.authorizationEndpoints[AuthPlatformMicrosoft] + params.Encode())
|
|
|
|
|
|
|
|
|
|
//http.Redirect(w, r, "https://appleid.apple.com/auth/authorize?"+params.Encode(), http.StatusSeeOther)
|
|
|
|
|
http.Redirect(w, r, mg.authorizationEndpoints[AuthPlatformMicrosoft]+"?"+params.Encode(), http.StatusSeeOther)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (mg *Maingate) platform_microsoft_authorize(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
defer r.Body.Close()
|
|
|
|
|
code := r.URL.Query().Get("code")
|
|
|
|
|
|
|
|
|
|
// set cookie for storing token
|
|
|
|
|
cookie := http.Cookie{
|
|
|
|
|
Name: "LoginFlowContext_code",
|
|
|
|
|
Value: code,
|
|
|
|
|
Expires: time.Now().Add(1 * time.Minute),
|
|
|
|
|
SameSite: http.SameSiteLaxMode,
|
|
|
|
|
Secure: true,
|
|
|
|
|
Path: "/",
|
|
|
|
|
}
|
|
|
|
|
http.SetCookie(w, &cookie)
|
|
|
|
|
|
2023-12-06 16:35:55 +09:00
|
|
|
http.Redirect(w, r, config.RedirectBaseUrl+"/authorize_result/"+AuthPlatformMicrosoft, http.StatusSeeOther) //-- 바로 받으니까 쿠키 안와서 한번 더 Redirect 시킨다.
|
2023-05-24 12:16:03 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (mg *Maingate) platform_microsoft_authorize_result(w http.ResponseWriter, r *http.Request) {
|
|
|
|
|
|
|
|
|
|
brinfo, err := mg.GetUserBrowserInfo(r)
|
|
|
|
|
if err != nil {
|
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
logger.Error(err)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cookie, err := r.Cookie("LoginFlowContext_SessionKey")
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Println("Session not found", err)
|
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cookiecode, err := r.Cookie("LoginFlowContext_code")
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Println("code not found", err)
|
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
code := cookiecode.Value
|
|
|
|
|
|
|
|
|
|
found, err := mg.mongoClient.FindOne(CollectionPlatformLoginToken, bson.M{
|
|
|
|
|
"key": cookie.Value,
|
|
|
|
|
"platform": AuthPlatformMicrosoft,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Println("LoginFlowContext_SessionKey find key :", err)
|
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if found == nil {
|
|
|
|
|
logger.Println("LoginFlowContext_SessionKey not found")
|
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cookie.Value != found["key"] {
|
|
|
|
|
logger.Println("LoginFlowContext_SessionKey key not match")
|
|
|
|
|
logger.Println(cookie.Value)
|
|
|
|
|
logger.Println(found["key"])
|
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if brinfo != found["brinfo"] { //-- 로그인 시작점과 인증점의 브라우저 혹은 접속지 정보가 다르다?
|
|
|
|
|
logger.Println("LoginFlowContext_SessionKey brinfo not match ")
|
|
|
|
|
logger.Println(brinfo)
|
|
|
|
|
logger.Println(found["brinfo"])
|
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//=================
|
|
|
|
|
|
|
|
|
|
params := url.Values{}
|
2023-12-06 16:35:55 +09:00
|
|
|
params.Add("client_id", config.MicrosoftClientId)
|
|
|
|
|
params.Add("redirect_uri", config.RedirectBaseUrl+"/authorize/"+AuthPlatformMicrosoft)
|
2023-05-24 12:16:03 +09:00
|
|
|
params.Add("code", code)
|
|
|
|
|
params.Add("scope", "openid offline_access https://graph.microsoft.com/mail.read")
|
|
|
|
|
params.Add("grant_type", "authorization_code")
|
|
|
|
|
|
2023-12-06 16:35:55 +09:00
|
|
|
params.Add("client_secret", config.MicrosoftClientSecret)
|
2023-05-24 12:16:03 +09:00
|
|
|
|
|
|
|
|
var respReferesh Microsoft_ValidationResponse
|
|
|
|
|
acceestoken_expire_time := time.Now().Unix()
|
|
|
|
|
content := params.Encode()
|
|
|
|
|
resp, _ := http.Post(mg.tokenEndpoints[AuthPlatformMicrosoft], "application/x-www-form-urlencoded", bytes.NewBuffer([]byte(content)))
|
|
|
|
|
if resp != nil {
|
|
|
|
|
body, _ := io.ReadAll(resp.Body)
|
|
|
|
|
// w.Write(body)
|
|
|
|
|
//json.NewDecoder(resp.Body).Decode(respReferesh)
|
|
|
|
|
json.Unmarshal(body, &respReferesh)
|
|
|
|
|
} else {
|
|
|
|
|
logger.Println("tokenEndpoints fail.")
|
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// fmt.Println("==============================")
|
|
|
|
|
// fmt.Println("IDToken:", respReferesh.IDToken)
|
|
|
|
|
// fmt.Println("AccessToken:", respReferesh.AccessToken)
|
|
|
|
|
// fmt.Println("ExpiresIn:", respReferesh.ExpiresIn)
|
|
|
|
|
// fmt.Println("RefreshToken:", respReferesh.RefreshToken)
|
|
|
|
|
// fmt.Println("TokenType:", respReferesh.TokenType)
|
|
|
|
|
// fmt.Println("==============================")
|
|
|
|
|
|
|
|
|
|
acceestoken_expire_time = acceestoken_expire_time + (int64(respReferesh.ExpiresIn) * 3 / 4) //--- 3/4 이상 지나면 업데이트 한다. ms는 보통 3600초 1시간
|
|
|
|
|
|
|
|
|
|
userid, _, nonce := JWTparseCode(mg.jwksUri[AuthPlatformMicrosoft], respReferesh.IDToken)
|
|
|
|
|
|
|
|
|
|
if nonce == "" || nonce != found["nonce"] {
|
|
|
|
|
logger.Errorf("nonce not match")
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if userid != "" {
|
|
|
|
|
var info usertokeninfo
|
|
|
|
|
info.platform = AuthPlatformMicrosoft
|
|
|
|
|
info.userid = userid
|
|
|
|
|
info.token = respReferesh.RefreshToken
|
|
|
|
|
info.brinfo = brinfo
|
|
|
|
|
info.accesstoken = respReferesh.AccessToken
|
|
|
|
|
info.accesstoken_expire_time = acceestoken_expire_time
|
2024-01-09 14:43:23 +09:00
|
|
|
info.email = ""
|
2023-05-24 12:16:03 +09:00
|
|
|
mg.setUserToken(info)
|
|
|
|
|
|
|
|
|
|
params := url.Values{}
|
|
|
|
|
params.Add("id", userid)
|
|
|
|
|
params.Add("authtype", AuthPlatformMicrosoft)
|
|
|
|
|
http.Redirect(w, r, "actionsquare://login?"+params.Encode(), http.StatusSeeOther)
|
|
|
|
|
} else {
|
|
|
|
|
http.Redirect(w, r, "actionsquare://error", http.StatusSeeOther)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (mg *Maingate) platform_microsoft_getuserinfo(info usertokeninfo) (bool, string, string) {
|
|
|
|
|
|
|
|
|
|
// fmt.Println(info.platform)
|
|
|
|
|
// fmt.Println(info.userid)
|
|
|
|
|
// fmt.Println(info.accesstoken)
|
|
|
|
|
|
|
|
|
|
// fmt.Println(time.Now().Unix())
|
|
|
|
|
// fmt.Println(info.accesstoken_expire_time)
|
|
|
|
|
|
|
|
|
|
//-- access token 갱신이 필요하다. -- userinfoEndpoint
|
|
|
|
|
if time.Now().Unix() > info.accesstoken_expire_time {
|
|
|
|
|
|
|
|
|
|
params := url.Values{}
|
2023-12-06 16:35:55 +09:00
|
|
|
params.Add("client_id", config.MicrosoftClientId)
|
|
|
|
|
params.Add("redirect_uri", config.RedirectBaseUrl+"/authorize/"+AuthPlatformMicrosoft)
|
2023-05-24 12:16:03 +09:00
|
|
|
params.Add("refresh_token", info.token)
|
|
|
|
|
params.Add("scope", "openid offline_access https://graph.microsoft.com/mail.read")
|
|
|
|
|
params.Add("grant_type", "refresh_token")
|
|
|
|
|
|
2023-12-06 16:35:55 +09:00
|
|
|
params.Add("client_secret", config.MicrosoftClientSecret)
|
2023-05-24 12:16:03 +09:00
|
|
|
|
|
|
|
|
var respReferesh Microsoft_ValidationResponse
|
|
|
|
|
acceestoken_expire_time := time.Now().Unix()
|
|
|
|
|
|
|
|
|
|
content := params.Encode()
|
|
|
|
|
resp, _ := http.Post(mg.tokenEndpoints[AuthPlatformMicrosoft], "application/x-www-form-urlencoded", bytes.NewBuffer([]byte(content)))
|
|
|
|
|
if resp != nil {
|
|
|
|
|
body, _ := io.ReadAll(resp.Body)
|
|
|
|
|
json.Unmarshal(body, &respReferesh)
|
|
|
|
|
|
|
|
|
|
// fmt.Println("==== accesstoken 업데이트 =====")
|
|
|
|
|
// fmt.Println("IDToken:", respReferesh.IDToken)
|
|
|
|
|
// fmt.Println("AccessToken:", respReferesh.AccessToken)
|
|
|
|
|
// fmt.Println("ExpiresIn:", respReferesh.ExpiresIn)
|
|
|
|
|
// fmt.Println("RefreshToken:", respReferesh.RefreshToken)
|
|
|
|
|
// fmt.Println("TokenType:", respReferesh.TokenType)
|
|
|
|
|
// fmt.Println("==============================")
|
|
|
|
|
|
|
|
|
|
acceestoken_expire_time = acceestoken_expire_time + (int64(respReferesh.ExpiresIn) * 3 / 4) //--- 3/4 이상 지나면 업데이트 한다. ms는 보통 3600초 1시간
|
|
|
|
|
|
|
|
|
|
userid, _, _ := JWTparseCode(mg.jwksUri[AuthPlatformMicrosoft], respReferesh.IDToken)
|
|
|
|
|
if userid != "" && info.userid == userid {
|
|
|
|
|
info.token = respReferesh.RefreshToken
|
|
|
|
|
info.accesstoken = respReferesh.AccessToken
|
|
|
|
|
info.accesstoken_expire_time = acceestoken_expire_time
|
2024-01-09 14:43:23 +09:00
|
|
|
info.email = ""
|
2023-05-24 12:16:03 +09:00
|
|
|
mg.setUserToken(info) //-- accesstoken 업데이트
|
|
|
|
|
} else {
|
|
|
|
|
logger.Println("JWTparseCode fail.")
|
|
|
|
|
return false, "", ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
logger.Println("tokenEndpoints fail.")
|
|
|
|
|
return false, "", ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//=================
|
|
|
|
|
|
|
|
|
|
req, _ := http.NewRequest("GET", mg.userinfoEndpoint[AuthPlatformMicrosoft], nil)
|
|
|
|
|
req.Header.Add("Authorization", "Bearer "+info.accesstoken)
|
|
|
|
|
|
|
|
|
|
client := http.Client{}
|
|
|
|
|
resp, err := client.Do(req)
|
|
|
|
|
if err != nil {
|
|
|
|
|
logger.Error("authorize query failed :", err)
|
|
|
|
|
return false, "", ""
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
var respUserInfo Microsoft_UserInfoResponse
|
|
|
|
|
|
|
|
|
|
body, _ := io.ReadAll(resp.Body)
|
|
|
|
|
json.Unmarshal(body, &respUserInfo)
|
|
|
|
|
|
|
|
|
|
// fmt.Println(string(body))
|
|
|
|
|
// fmt.Println(respUserInfo.Sub)
|
|
|
|
|
// fmt.Println(respUserInfo.Email)
|
|
|
|
|
|
|
|
|
|
if respUserInfo.Sub != info.userid {
|
|
|
|
|
logger.Println("userinfoEndpoint fail.")
|
|
|
|
|
return false, "", ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true, info.userid, respUserInfo.Email //?
|
|
|
|
|
|
|
|
|
|
}
|