1
0
mirror of https://github.com/go-micro/go-micro.git synced 2025-08-10 21:52:01 +02:00

Merge branch 'master' into auth-resolver

This commit is contained in:
ben-toogood
2020-04-03 14:19:03 +01:00
committed by GitHub
11 changed files with 211 additions and 85 deletions

View File

@@ -2,6 +2,7 @@ package auth
import (
"fmt"
"net"
"net/http"
"net/url"
"strings"
@@ -9,6 +10,7 @@ import (
"github.com/micro/go-micro/v2/api/resolver"
"github.com/micro/go-micro/v2/api/resolver/path"
"github.com/micro/go-micro/v2/auth"
"github.com/micro/go-micro/v2/logger"
)
// CombinedAuthHandler wraps a server and authenticates requests
@@ -36,6 +38,16 @@ type authHandler struct {
}
func (h authHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// Determine the namespace
namespace, err := namespaceFromRequest(req)
if err != nil {
logger.Error(err)
namespace = auth.DefaultNamespace
}
// Set the namespace in the header
req.Header.Set(auth.NamespaceKey, namespace)
// Extract the token from the request
var token string
if header := req.Header.Get("Authorization"); len(header) > 0 {
@@ -56,7 +68,14 @@ func (h authHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// account doesn't necesserially mean a forbidden request
acc, err := h.auth.Inspect(token)
if err != nil {
acc = &auth.Account{}
acc = &auth.Account{Namespace: namespace}
}
// Check the accounts namespace matches the namespace we're operating
// within. If not forbid the request and log the occurance.
if acc.Namespace != namespace {
logger.Warnf("Cross namespace request forbidden: account %v (%v) requested access to %v in the %v namespace", acc.ID, acc.Namespace, req.URL.Path, namespace)
w.WriteHeader(http.StatusForbidden)
}
// Determine the name of the service being requested
@@ -85,15 +104,15 @@ func (h authHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
// Perform the verification check to see if the account has access to
// the resource they're requesting
res := &auth.Resource{Type: "service", Name: resName, Endpoint: resEndpoint}
res := &auth.Resource{Type: "service", Name: resName, Endpoint: resEndpoint, Namespace: namespace}
if err := h.auth.Verify(acc, res); err == nil {
// The account has the necessary permissions to access the resource
h.handler.ServeHTTP(w, req)
return
}
// The account is set, but they don't have enough permissions,
// hence we 403.
// The account is set, but they don't have enough permissions, hence
// we return a forbidden error.
if len(acc.ID) > 0 {
w.WriteHeader(http.StatusForbidden)
return
@@ -111,3 +130,42 @@ func (h authHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
loginWithRedirect := fmt.Sprintf("%v?%v", loginURL, params.Encode())
http.Redirect(w, req, loginWithRedirect, http.StatusTemporaryRedirect)
}
func namespaceFromRequest(req *http.Request) (string, error) {
// determine the host, e.g. dev.micro.mu:8080
host := req.URL.Host
if len(host) == 0 {
host = req.Host
}
// check for an ip address
if net.ParseIP(host) != nil {
return auth.DefaultNamespace, nil
}
// split the host to remove the port
host, _, err := net.SplitHostPort(req.Host)
if err != nil {
return "", err
}
// check for dev enviroment
if host == "localhost" || host == "127.0.0.1" {
return auth.DefaultNamespace, nil
}
// if host is not a subdomain, deturn default namespace
comps := strings.Split(host, ".")
if len(comps) != 3 {
return auth.DefaultNamespace, nil
}
// check for the micro.mu domain
domain := fmt.Sprintf("%v.%v", comps[1], comps[2])
if domain == "micro.mu" {
return auth.DefaultNamespace, nil
}
// return the subdomain as the host
return comps[0], nil
}