package controllers import ( "encoding/base64" "encoding/json" "fmt" "net/http" "oc-auth/conf" "oc-auth/infrastructure" auth_connectors "oc-auth/infrastructure/auth_connector" "oc-auth/infrastructure/claims" "regexp" "strings" "time" oclib "cloud.o-forge.io/core/oc-lib" model "cloud.o-forge.io/core/oc-lib/models/peer" beego "github.com/beego/beego/v2/server/web" ) // Operations about auth type OAuthController struct { beego.Controller } // @Title Logout // @Description unauthenticate user // @Param Authorization header string false "auth token" // @Param client_id query string true "the client_id you want to get" // @Success 200 {string} // @router /logout [delete] func (o *OAuthController) LogOut() { // authorize user clientID := o.Ctx.Input.Query("client_id") reqToken := o.Ctx.Request.Header.Get("Authorization") splitToken := strings.Split(reqToken, "Bearer ") if len(splitToken) < 2 { reqToken = "" } else { reqToken = splitToken[1] } var res auth_connectors.Token json.Unmarshal(o.Ctx.Input.CopyBody(10000000), &res) if !conf.GetConfig().Local { token, err := infrastructure.GetAuthConnector().Logout(clientID, reqToken) if err != nil || token == nil { o.Data["json"] = err } else { o.Data["json"] = token } } else { o.Data["json"] = reqToken } o.ServeJSON() } // @Title Login // @Description authenticate user // @Param body body models.workflow true "The workflow content" // @Param client_id query string true "the client_id you want to get" // @Success 200 {string} // @router /login [post] func (o *OAuthController) Login() { // authorize user clientID := o.Ctx.Input.Query("client_id") var res auth_connectors.Token json.Unmarshal(o.Ctx.Input.CopyBody(10000000), &res) if conf.GetConfig().SourceMode == "ldap" { ldap := auth_connectors.New() found, err := ldap.Authenticate(o.Ctx.Request.Context(), res.Username, res.Password) if err != nil || !found { o.Data["json"] = err o.Ctx.ResponseWriter.WriteHeader(401) o.ServeJSON() return } } if !conf.GetConfig().Local { token, err := infrastructure.GetAuthConnector().Login( clientID, res.Username, &http.Cookie{ // open a session Name: "csrf_token", Value: o.XSRFToken(), }) if err != nil || token == nil { o.Data["json"] = err o.Ctx.ResponseWriter.WriteHeader(401) } else { o.Data["json"] = token } } else { t := oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), "", "", []string{}, nil).Search( nil, fmt.Sprintf("%v", model.SELF.EnumIndex()), false) if t.Err == "" && len(t.Data) > 0 { token := &auth_connectors.Token{ Username: res.Username, Password: res.Password, TokenType: "Bearer", Active: true, ExpiresIn: 3600, AccessToken: "localtoken", } now := time.Now().UTC() now = now.Add(time.Duration(token.ExpiresIn) * time.Second) unix := now.Unix() c := claims.GetClaims().AddClaimsToToken(clientID, res.Username, t.Data[0].(*model.Peer)) c.Session.AccessToken["exp"] = unix b, _ := json.Marshal(c) token.AccessToken = token.AccessToken + "." + base64.StdEncoding.EncodeToString(b) o.Data["json"] = token } else { o.Data["json"] = t.Err o.Ctx.ResponseWriter.WriteHeader(401) } } o.ServeJSON() } // @Title Introspection // @Description introspect token // @Param body body models.Token true "The token info" // @Param client_id query string true "the client_id you want to get" // @Success 200 {string} // @router /refresh [post] func (o *OAuthController) Refresh() { clientID := o.Ctx.Input.Query("client_id") var token auth_connectors.Token json.Unmarshal(o.Ctx.Input.CopyBody(100000), &token) // refresh token if !conf.GetConfig().Local { newToken, err := infrastructure.GetAuthConnector().Refresh(clientID, &token) if err != nil || newToken == nil { o.Data["json"] = err o.Ctx.ResponseWriter.WriteHeader(401) } else { o.Data["json"] = newToken } } else { o.Data["json"] = token } o.ServeJSON() } // @Title Introspection // @Description introspect token // @Param Authorization header string false "auth token" // @Success 200 {string} // @router /introspect [get] func (o *OAuthController) Introspect() { reqToken := o.Ctx.Request.Header.Get("Authorization") splitToken := strings.Split(reqToken, "Bearer ") if len(splitToken) < 2 { reqToken = "" } else { reqToken = splitToken[1] } if !conf.GetConfig().Local { token, err := infrastructure.GetAuthConnector().Introspect(reqToken) if err != nil || !token { o.Data["json"] = err o.Ctx.ResponseWriter.WriteHeader(401) } } o.ServeJSON() } var whitelist = []string{ "/login", "/refresh", "/introspect", } // @Title AuthForward // @Description auth forward // @Param Authorization header string false "auth token" // @Success 200 {string} // @router /forward [get] func (o *OAuthController) InternalAuthForward() { fmt.Println("InternalAuthForward") reqToken := o.Ctx.Request.Header.Get("Authorization") if reqToken == "" { for _, w := range whitelist { if strings.Contains(o.Ctx.Request.Header.Get("X-Forwarded-Uri"), w) { o.Ctx.ResponseWriter.WriteHeader(200) o.ServeJSON() return } } o.Ctx.ResponseWriter.WriteHeader(401) o.ServeJSON() return } splitToken := strings.Split(reqToken, "Bearer ") if len(splitToken) < 2 { reqToken = "" } else { reqToken = splitToken[1] } origin, publicKey, external := o.extractOrigin(o.Ctx.Request) if !infrastructure.GetAuthConnector().CheckAuthForward( //reqToken != "" && reqToken, publicKey, origin, o.Ctx.Request.Header.Get("X-Forwarded-Method"), o.Ctx.Request.Header.Get("X-Forwarded-Uri"), external) && origin != "" && publicKey != "" { o.Ctx.ResponseWriter.WriteHeader(401) o.ServeJSON() return } o.ServeJSON() } func (o *OAuthController) extractOrigin(request *http.Request) (string, string, bool) { user, peerID, groups := oclib.ExtractTokenInfo(*request) external := true publicKey := "" origin := o.Ctx.Request.Header.Get("X-Forwarded-Host") if origin == "" { origin = o.Ctx.Request.Header.Get("Origin") } searchStr := origin r := regexp.MustCompile("(:[0-9]+)") t := r.FindString(searchStr) if t != "" { searchStr = strings.Replace(searchStr, t, "", -1) } peer := oclib.NewRequest(oclib.LibDataEnum(oclib.PEER), user, peerID, groups, nil).Search(nil, searchStr, false) if peer.Code != 200 || len(peer.Data) == 0 { // TODO: add state of partnership return "", "", external } p := peer.Data[0].(*model.Peer) publicKey = p.PublicKey origin = p.Url if origin != "" { // is external if strings.Contains(origin, "localhost") || strings.Contains(origin, "127.0.0.1") || p.State == model.SELF { external = false } } else { external = false } return origin, publicKey, external } func ExtractClient(request http.Request) string { reqToken := request.Header.Get("Authorization") splitToken := strings.Split(reqToken, "Bearer ") if len(splitToken) < 2 { reqToken = "" } else { reqToken = splitToken[1] } if reqToken != "" { token := strings.Split(reqToken, ".") if len(token) > 2 { bytes, err := base64.StdEncoding.DecodeString(token[2]) if err != nil { return "" } m := map[string]interface{}{} err = json.Unmarshal(bytes, &m) if err != nil { return "" } return m["session"].(map[string]interface{})["id_token"].(map[string]interface{})["client_id"].(string) } } return "" }