oc-auth/controllers/oauth2.go

226 lines
6.5 KiB
Go
Raw Normal View History

package controllers
import (
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"oc-auth/infrastructure"
auth_connectors "oc-auth/infrastructure/auth_connector"
"oc-auth/infrastructure/claims"
"strings"
oclib "cloud.o-forge.io/core/oc-lib"
model "cloud.o-forge.io/core/oc-lib/models/peer"
"cloud.o-forge.io/core/oc-lib/static"
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"
// @Success 200 {string}
// @router /ldap/logout [delete]
func (o *OAuthController) LogOutLDAP() {
// authorize user
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)
token, err := infrastructure.GetAuthConnector().Logout(reqToken)
if err != nil || token == nil {
o.Data["json"] = err
} else {
o.Data["json"] = token
}
o.ServeJSON()
}
// @Title Login
// @Description authenticate user
// @Param body body models.workflow true "The workflow content"
// @Success 200 {string}
// @router /ldap/login [post]
func (o *OAuthController) LoginLDAP() {
// authorize user
var res auth_connectors.Token
json.Unmarshal(o.Ctx.Input.CopyBody(10000000), &res)
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
}
token, err := infrastructure.GetAuthConnector().Login(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
}
o.ServeJSON()
}
// @Title Claims
// @Description enrich token with claims
// @Param body body models.Token true "The token info"
// @Success 200 {string}
// @router /claims [post]
func (o *OAuthController) Claims() {
// enrich token with claims
var res claims.Claims
json.Unmarshal(o.Ctx.Input.CopyBody(100000), &res)
claims := res.Session.IDToken["id_token_claims"].(map[string]interface{})
userName := claims["sub"].(string)
_, loc := static.GetMyLocalJsonPeer()
o.Data["json"] = infrastructure.GetClaims().AddClaimsToToken(userName, loc["url"].(string))
o.ServeJSON()
}
// @Title Introspection
// @Description introspect token
// @Param body body models.Token true "The token info"
// @Success 200 {string}
// @router /refresh [post]
func (o *OAuthController) Refresh() {
var token auth_connectors.Token
json.Unmarshal(o.Ctx.Input.CopyBody(100000), &token)
// refresh token
newToken, err := infrastructure.GetAuthConnector().Refresh(&token)
if err != nil || newToken == nil {
o.Data["json"] = err
o.Ctx.ResponseWriter.WriteHeader(401)
} else {
o.Data["json"] = newToken
}
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]
}
token, err := infrastructure.GetAuthConnector().Introspect(reqToken)
if err != nil || !token {
o.Data["json"] = err
o.Ctx.ResponseWriter.WriteHeader(401)
}
o.ServeJSON()
}
// @Title AuthForward
// @Description auth forward
// @Param Authorization header string false "auth token"
// @Param body body models.workflow true "The workflow content"
// @Success 200 {string}
// @router /forward [get]
func (o *OAuthController) InternalAuthForward() {
reqToken := o.Ctx.Request.Header.Get("Authorization")
splitToken := strings.Split(reqToken, "Bearer ")
if len(splitToken) < 2 {
reqToken = ""
} else {
reqToken = splitToken[1]
}
origin, publicKey, external := o.extractOrigin()
if reqToken != "" && !o.checkAuthForward(reqToken, publicKey) && origin != "" {
fmt.Println("Unauthorized", origin, reqToken)
o.Ctx.ResponseWriter.WriteHeader(401)
o.ServeJSON()
return
}
token, err := infrastructure.GetAuthConnector().Introspect(reqToken, &http.Cookie{
Name: "csrf_token",
Value: o.XSRFToken(),
}) // may be a problem... we should check if token is valid on our side
// prefers a refresh token call
if err != nil || external {
fmt.Println("Unauthorized 2", err, external) // error
o.Ctx.ResponseWriter.WriteHeader(401)
} else if token && !external { // redirect to login
o.Data["json"] = token
}
o.ServeJSON()
}
func (o *OAuthController) extractOrigin() (string, string, bool) {
external := true
publicKey := ""
origin := o.Ctx.Request.Header.Get("X-Forwarded-Host")
if origin == "" {
origin = o.Ctx.Request.Header.Get("Origin")
}
idLoc, loc := static.GetMyLocalJsonPeer()
if origin != "" { // is external
peer := oclib.Search(nil, origin, oclib.LibDataEnum(oclib.PEER))
if peer.Code != 200 {
return "", "", external
}
p := peer.Data[0]
if strings.Contains(origin, "localhost") || strings.Contains(origin, "127.0.0.1") || idLoc == p.GetID() {
external = false
}
publicKey = p.(*model.Peer).PublicKey
} else {
external = false
publicKey = loc["public_key"].(string)
}
return origin, publicKey, external
}
func (o *OAuthController) checkAuthForward(reqToken string, publicKey string) bool {
bytes, err := base64.StdEncoding.DecodeString(reqToken) // Converting data
if err != nil {
fmt.Println("Failed to Decode secret", err)
return false
}
var decodedToken map[string]interface{}
err = json.Unmarshal(bytes, &decodedToken)
if err != nil {
fmt.Println("Failed to parse secret", err)
return false
} else if decodedToken["session"] != nil {
host := o.Ctx.Request.Header.Get("X-Forwarded-Host")
method := o.Ctx.Request.Header.Get("X-Forwarded-Method")
forward := o.Ctx.Request.Header.Get("X-Forwarded-Uri")
if forward == "" || method == "" {
fmt.Println("Forwarded headers are missing")
return false
}
// ask keto for permission is in claims
ok, err := infrastructure.GetClaims().DecodeClaimsInToken(
host, method, forward, decodedToken["session"].(map[string]interface{}), publicKey)
if err != nil {
fmt.Println("Failed to decode claims", err)
}
return ok
}
return false
}