|
|
|
|
@ -34,6 +34,15 @@ func checkCredential(right string, guess string) bool {
@@ -34,6 +34,15 @@ func checkCredential(right string, guess string) bool {
|
|
|
|
|
return right == guess |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type errAuthentication struct { |
|
|
|
|
message string |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Error implements the error interface.
|
|
|
|
|
func (e *errAuthentication) Error() string { |
|
|
|
|
return "authentication failed: " + e.message |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type authProtocol string |
|
|
|
|
|
|
|
|
|
const ( |
|
|
|
|
@ -43,16 +52,23 @@ const (
@@ -43,16 +52,23 @@ const (
|
|
|
|
|
authProtocolWebRTC authProtocol = "webrtc" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
func externalAuth( |
|
|
|
|
type authCredentials struct { |
|
|
|
|
query string |
|
|
|
|
ip net.IP |
|
|
|
|
user string |
|
|
|
|
pass string |
|
|
|
|
proto authProtocol |
|
|
|
|
id *uuid.UUID |
|
|
|
|
rtspRequest *base.Request |
|
|
|
|
rtspBaseURL *url.URL |
|
|
|
|
rtspNonce string |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func doExternalAuthentication( |
|
|
|
|
ur string, |
|
|
|
|
ip string, |
|
|
|
|
user string, |
|
|
|
|
password string, |
|
|
|
|
path string, |
|
|
|
|
protocol authProtocol, |
|
|
|
|
id *uuid.UUID, |
|
|
|
|
publish bool, |
|
|
|
|
query string, |
|
|
|
|
credentials authCredentials, |
|
|
|
|
) error { |
|
|
|
|
enc, _ := json.Marshal(struct { |
|
|
|
|
IP string `json:"ip"` |
|
|
|
|
@ -64,19 +80,19 @@ func externalAuth(
@@ -64,19 +80,19 @@ func externalAuth(
|
|
|
|
|
Action string `json:"action"` |
|
|
|
|
Query string `json:"query"` |
|
|
|
|
}{ |
|
|
|
|
IP: ip, |
|
|
|
|
User: user, |
|
|
|
|
Password: password, |
|
|
|
|
IP: credentials.ip.String(), |
|
|
|
|
User: credentials.user, |
|
|
|
|
Password: credentials.pass, |
|
|
|
|
Path: path, |
|
|
|
|
Protocol: string(protocol), |
|
|
|
|
ID: id, |
|
|
|
|
Protocol: string(credentials.proto), |
|
|
|
|
ID: credentials.id, |
|
|
|
|
Action: func() string { |
|
|
|
|
if publish { |
|
|
|
|
return "publish" |
|
|
|
|
} |
|
|
|
|
return "read" |
|
|
|
|
}(), |
|
|
|
|
Query: query, |
|
|
|
|
Query: credentials.query, |
|
|
|
|
}) |
|
|
|
|
res, err := http.Post(ur, "application/json", bytes.NewReader(enc)) |
|
|
|
|
if err != nil { |
|
|
|
|
@ -86,28 +102,15 @@ func externalAuth(
@@ -86,28 +102,15 @@ func externalAuth(
|
|
|
|
|
|
|
|
|
|
if res.StatusCode < 200 || res.StatusCode > 299 { |
|
|
|
|
if resBody, err := io.ReadAll(res.Body); err == nil && len(resBody) != 0 { |
|
|
|
|
return fmt.Errorf("external authentication replied with code %d: %s", res.StatusCode, string(resBody)) |
|
|
|
|
return fmt.Errorf("server replied with code %d: %s", res.StatusCode, string(resBody)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return fmt.Errorf("external authentication replied with code %d", res.StatusCode) |
|
|
|
|
return fmt.Errorf("server replied with code %d", res.StatusCode) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type authCredentials struct { |
|
|
|
|
query string |
|
|
|
|
ip net.IP |
|
|
|
|
user string |
|
|
|
|
pass string |
|
|
|
|
proto authProtocol |
|
|
|
|
id *uuid.UUID |
|
|
|
|
rtspRequest *base.Request |
|
|
|
|
rtspBaseURL *url.URL |
|
|
|
|
rtspNonce string |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func authenticate( |
|
|
|
|
func doAuthentication( |
|
|
|
|
externalAuthenticationURL string, |
|
|
|
|
rtspAuthMethods conf.AuthMethods, |
|
|
|
|
pathName string, |
|
|
|
|
@ -125,19 +128,14 @@ func authenticate(
@@ -125,19 +128,14 @@ func authenticate(
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if externalAuthenticationURL != "" { |
|
|
|
|
err := externalAuth( |
|
|
|
|
err := doExternalAuthentication( |
|
|
|
|
externalAuthenticationURL, |
|
|
|
|
credentials.ip.String(), |
|
|
|
|
credentials.user, |
|
|
|
|
credentials.pass, |
|
|
|
|
pathName, |
|
|
|
|
credentials.proto, |
|
|
|
|
credentials.id, |
|
|
|
|
publish, |
|
|
|
|
credentials.query, |
|
|
|
|
credentials, |
|
|
|
|
) |
|
|
|
|
if err != nil { |
|
|
|
|
return fmt.Errorf("external authentication failed: %s", err) |
|
|
|
|
return &errAuthentication{message: fmt.Sprintf("external authentication failed: %s", err)} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -157,7 +155,7 @@ func authenticate(
@@ -157,7 +155,7 @@ func authenticate(
|
|
|
|
|
|
|
|
|
|
if pathIPs != nil { |
|
|
|
|
if !ipEqualOrInRange(credentials.ip, pathIPs) { |
|
|
|
|
return fmt.Errorf("IP '%s' not allowed", credentials.ip) |
|
|
|
|
return &errAuthentication{message: fmt.Sprintf("IP %s not allowed", credentials.ip)} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -172,11 +170,11 @@ func authenticate(
@@ -172,11 +170,11 @@ func authenticate(
|
|
|
|
|
"IPCAM", |
|
|
|
|
credentials.rtspNonce) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
return &errAuthentication{message: err.Error()} |
|
|
|
|
} |
|
|
|
|
} else if !checkCredential(pathUser, credentials.user) || |
|
|
|
|
!checkCredential(pathPass, credentials.pass) { |
|
|
|
|
return fmt.Errorf("invalid credentials") |
|
|
|
|
return &errAuthentication{message: "invalid credentials"} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|