mirror of
https://github.com/ossrs/srs.git
synced 2025-02-12 19:31:53 +00:00
API: Support HTTP basic authentication for API. v6.0.4, v5.0.152 (#3458)
Co-authored-by: winlin <winlin@vip.126.com> Co-authored-by: john <hondaxiao@tencent.com>
This commit is contained in:
parent
571043ff3d
commit
771ae0a1a6
15 changed files with 660 additions and 50 deletions
93
trunk/3rdparty/srs-bench/blackbox/http_api_test.go
vendored
Normal file
93
trunk/3rdparty/srs-bench/blackbox/http_api_test.go
vendored
Normal file
|
@ -0,0 +1,93 @@
|
|||
// The MIT License (MIT)
|
||||
//
|
||||
// # Copyright (c) 2023 Winlin
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
package blackbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/ossrs/go-oryx-lib/errors"
|
||||
"github.com/ossrs/go-oryx-lib/logger"
|
||||
"net/http"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestFast_Http_Api_Basic_Auth(t *testing.T) {
|
||||
// This case is run in parallel.
|
||||
t.Parallel()
|
||||
|
||||
// Setup the max timeout for this case.
|
||||
ctx, cancel := context.WithTimeout(logger.WithContext(context.Background()), time.Duration(*srsTimeout)*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
// Check a set of errors.
|
||||
var r0, r1, r2, r3, r4, r5, r6 error
|
||||
defer func(ctx context.Context) {
|
||||
if err := filterTestError(ctx.Err(), r0, r1, r2, r3, r4, r5, r6); err != nil {
|
||||
t.Errorf("Fail for err %+v", err)
|
||||
} else {
|
||||
logger.Tf(ctx, "test done with err %+v", err)
|
||||
}
|
||||
}(ctx)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
defer wg.Wait()
|
||||
|
||||
// Start SRS server and wait for it to be ready.
|
||||
svr := NewSRSServer(func(v *srsServer) {
|
||||
v.envs = []string{
|
||||
"SRS_HTTP_API_AUTH_ENABLED=on",
|
||||
"SRS_HTTP_API_AUTH_USERNAME=admin",
|
||||
"SRS_HTTP_API_AUTH_PASSWORD=admin",
|
||||
}
|
||||
})
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
r0 = svr.Run(ctx, cancel)
|
||||
}()
|
||||
|
||||
<-svr.ReadyCtx().Done()
|
||||
|
||||
if true {
|
||||
defer cancel()
|
||||
|
||||
var res *http.Response
|
||||
url := fmt.Sprintf("http://admin:admin@localhost:%v/api/v1/versions", svr.APIPort())
|
||||
res, r1 = http.Get(url)
|
||||
if r1 == nil && res.StatusCode != 200 {
|
||||
r2 = errors.Errorf("get status code=%v, expect=200", res.StatusCode)
|
||||
}
|
||||
|
||||
url = fmt.Sprintf("http://admin:123456@localhost:%v/api/v1/versions", svr.APIPort())
|
||||
res, r3 = http.Get(url)
|
||||
if r3 == nil && res.StatusCode != 401 {
|
||||
r4 = errors.Errorf("get status code=%v, expect=401", res.StatusCode)
|
||||
}
|
||||
|
||||
url = fmt.Sprintf("http://localhost:%v/api/v1/versions", svr.APIPort())
|
||||
res, r5 = http.Get(url)
|
||||
if r5 == nil && res.StatusCode != 401 {
|
||||
r6 = errors.Errorf("get status code=%v, expect=401", res.StatusCode)
|
||||
}
|
||||
}
|
||||
}
|
36
trunk/3rdparty/srs-bench/blackbox/util.go
vendored
36
trunk/3rdparty/srs-bench/blackbox/util.go
vendored
|
@ -329,7 +329,7 @@ func (v *backendService) Run(ctx context.Context, cancel context.CancelFunc) err
|
|||
}
|
||||
|
||||
select {
|
||||
case <- ctx.Done():
|
||||
case <-ctx.Done():
|
||||
case <-time.After(v.duration):
|
||||
logger.Tf(ctx, "Process killed duration=%v, pid=%v, name=%v, args=%v", v.duration, v.pid, v.name, v.args)
|
||||
cmd.Process.Kill()
|
||||
|
@ -418,6 +418,8 @@ type SRSServer interface {
|
|||
RTMPPort() int
|
||||
// HTTPPort is the HTTP stream port.
|
||||
HTTPPort() int
|
||||
// APIPort is the HTTP API port.
|
||||
APIPort() int
|
||||
// SRTPort is the SRT UDP port.
|
||||
SRTPort() int
|
||||
}
|
||||
|
@ -510,6 +512,10 @@ func (v *srsServer) HTTPPort() int {
|
|||
return v.httpListen
|
||||
}
|
||||
|
||||
func (v *srsServer) APIPort() int {
|
||||
return v.apiListen
|
||||
}
|
||||
|
||||
func (v *srsServer) SRTPort() int {
|
||||
return v.srtListen
|
||||
}
|
||||
|
@ -524,7 +530,7 @@ func (v *srsServer) Run(ctx context.Context, cancel context.CancelFunc) error {
|
|||
)
|
||||
|
||||
// Create directories.
|
||||
if err := os.MkdirAll(path.Join(v.workDir, "./objs/nginx/html"), os.FileMode(0755) | os.ModeDir); err != nil {
|
||||
if err := os.MkdirAll(path.Join(v.workDir, "./objs/nginx/html"), os.FileMode(0755)|os.ModeDir); err != nil {
|
||||
return errors.Wrapf(err, "SRS create directory %v", path.Join(v.workDir, "./objs/nginx/html"))
|
||||
}
|
||||
|
||||
|
@ -657,7 +663,7 @@ type ffmpegClient struct {
|
|||
|
||||
func NewFFmpeg(opts ...func(v *ffmpegClient)) FFmpegClient {
|
||||
v := &ffmpegClient{
|
||||
process: newBackendService(),
|
||||
process: newBackendService(),
|
||||
cancelCaseWhenQuit: true,
|
||||
}
|
||||
|
||||
|
@ -701,7 +707,7 @@ func (v *ffmpegClient) Run(ctx context.Context, cancel context.CancelFunc) error
|
|||
ffCtx, ffCancel := context.WithCancel(ctx)
|
||||
go func() {
|
||||
select {
|
||||
case <- ctx.Done():
|
||||
case <-ctx.Done():
|
||||
case <-ffCtx.Done():
|
||||
if v.cancelCaseWhenQuit {
|
||||
cancel()
|
||||
|
@ -1144,17 +1150,17 @@ func (v *HooksEventBase) HookAction() string {
|
|||
|
||||
type HooksEventOnDvr struct {
|
||||
HooksEventBase
|
||||
Stream string `json:"stream"`
|
||||
Stream string `json:"stream"`
|
||||
StreamUrl string `json:"stream_url"`
|
||||
StreamID string `json:"stream_id"`
|
||||
CWD string `json:"cwd"`
|
||||
File string `json:"file"`
|
||||
TcUrl string `json:"tcUrl"`
|
||||
App string `json:"app"`
|
||||
Vhost string `json:"vhost"`
|
||||
IP string `json:"ip"`
|
||||
ClientIP string `json:"client_id"`
|
||||
ServerID string `json:"server_id"`
|
||||
StreamID string `json:"stream_id"`
|
||||
CWD string `json:"cwd"`
|
||||
File string `json:"file"`
|
||||
TcUrl string `json:"tcUrl"`
|
||||
App string `json:"app"`
|
||||
Vhost string `json:"vhost"`
|
||||
IP string `json:"ip"`
|
||||
ClientIP string `json:"client_id"`
|
||||
ServerID string `json:"server_id"`
|
||||
}
|
||||
|
||||
type HooksService interface {
|
||||
|
@ -1171,7 +1177,7 @@ type hooksService struct {
|
|||
httpPort int
|
||||
dispose func()
|
||||
|
||||
r0 error
|
||||
r0 error
|
||||
hooksOnDvr chan HooksEvent
|
||||
}
|
||||
|
||||
|
|
|
@ -203,6 +203,19 @@ http_api {
|
|||
# Always off by https://github.com/ossrs/srs/issues/2653
|
||||
#allow_update off;
|
||||
}
|
||||
# the auth is authentication for http api
|
||||
auth {
|
||||
# whether enable the HTTP AUTH.
|
||||
# Overwrite by env SRS_HTTP_API_AUTH_ENABLED
|
||||
# default: off
|
||||
enabled on;
|
||||
# The username of Basic authentication:
|
||||
# Overwrite by env SRS_HTTP_API_AUTH_USERNAME
|
||||
username admin;
|
||||
# The password of Basic authentication:
|
||||
# Overwrite by env SRS_HTTP_API_AUTH_PASSWORD
|
||||
password admin;
|
||||
}
|
||||
# For https_api or HTTPS API.
|
||||
https {
|
||||
# Whether enable HTTPS API.
|
||||
|
|
|
@ -8,6 +8,7 @@ The changelog for SRS.
|
|||
|
||||
## SRS 6.0 Changelog
|
||||
|
||||
* v5.0, 2023-04-01, Merge [#3458](https://github.com/ossrs/srs/pull/3450): API: Support HTTP basic authentication for API. v6.0.40 (#3458)
|
||||
* v6.0, 2023-03-27, Merge [#3450](https://github.com/ossrs/srs/pull/3450): WebRTC: Error message carries the SDP when failed. v6.0.39 (#3450)
|
||||
* v6.0, 2023-03-25, Merge [#3477](https://github.com/ossrs/srs/pull/3477): Remove unneccessary NULL check in srs_freep. v6.0.38 (#3477)
|
||||
* v6.0, 2023-03-25, Merge [#3455](https://github.com/ossrs/srs/pull/3455): RTC: Call on_play before create session, for it might be freed for timeout. v6.0.37 (#3455)
|
||||
|
@ -53,6 +54,7 @@ The changelog for SRS.
|
|||
|
||||
## SRS 5.0 Changelog
|
||||
|
||||
* v5.0, 2023-04-01, Merge [#3458](https://github.com/ossrs/srs/pull/3450): API: Support HTTP basic authentication for API. v5.0.152 (#3458)
|
||||
* v5.0, 2023-03-27, Merge [#3450](https://github.com/ossrs/srs/pull/3450): WebRTC: Error message carries the SDP when failed. v5.0.151 (#3450)
|
||||
* v5.0, 2023-03-25, Merge [#3477](https://github.com/ossrs/srs/pull/3477): Remove unneccessary NULL check in srs_freep. v5.0.150 (#3477)
|
||||
* v5.0, 2023-03-25, Merge [#3455](https://github.com/ossrs/srs/pull/3455): RTC: Call on_play before create session, for it might be freed for timeout. v5.0.149 (#3455)
|
||||
|
|
|
@ -2284,7 +2284,7 @@ srs_error_t SrsConfig::check_normal_config()
|
|||
for (int i = 0; conf && i < (int)conf->directives.size(); i++) {
|
||||
SrsConfDirective* obj = conf->at(i);
|
||||
string n = obj->name;
|
||||
if (n != "enabled" && n != "listen" && n != "crossdomain" && n != "raw_api" && n != "https") {
|
||||
if (n != "enabled" && n != "listen" && n != "crossdomain" && n != "raw_api" && n != "auth" && n != "https") {
|
||||
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal http_api.%s", n.c_str());
|
||||
}
|
||||
|
||||
|
@ -2296,6 +2296,15 @@ srs_error_t SrsConfig::check_normal_config()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (n == "auth") {
|
||||
for (int j = 0; j < (int)obj->directives.size(); j++) {
|
||||
string m = obj->at(j)->name;
|
||||
if (m != "enabled" && m != "username" && m != "password") {
|
||||
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "illegal http_api.auth.%s", m.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (true) {
|
||||
|
@ -7605,6 +7614,78 @@ bool SrsConfig::get_raw_api_allow_update()
|
|||
return false;
|
||||
}
|
||||
|
||||
bool SrsConfig::get_http_api_auth_enabled()
|
||||
{
|
||||
SRS_OVERWRITE_BY_ENV_BOOL("srs.http_api.auth.enabled"); // SRS_HTTP_API_AUTH_ENABLED
|
||||
|
||||
static bool DEFAULT = false;
|
||||
|
||||
SrsConfDirective* conf = root->get("http_api");
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
conf = conf->get("auth");
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
conf = conf->get("enabled");
|
||||
if (!conf || conf->arg0().empty()) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
return SRS_CONF_PERFER_FALSE(conf->arg0());
|
||||
}
|
||||
|
||||
std::string SrsConfig::get_http_api_auth_username()
|
||||
{
|
||||
SRS_OVERWRITE_BY_ENV_STRING("srs.http_api.auth.username"); // SRS_HTTP_API_AUTH_USERNAME
|
||||
|
||||
static string DEFAULT = "";
|
||||
|
||||
SrsConfDirective* conf = root->get("http_api");
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
conf = conf->get("auth");
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
conf = conf->get("username");
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
return conf->arg0();
|
||||
}
|
||||
|
||||
std::string SrsConfig::get_http_api_auth_password()
|
||||
{
|
||||
SRS_OVERWRITE_BY_ENV_STRING("srs.http_api.auth.password"); // SRS_HTTP_API_AUTH_PASSWORD
|
||||
|
||||
static string DEFAULT = "";
|
||||
|
||||
SrsConfDirective* conf = root->get("http_api");
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
conf = conf->get("auth");
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
conf = conf->get("password");
|
||||
if (!conf) {
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
return conf->arg0();
|
||||
}
|
||||
|
||||
SrsConfDirective* SrsConfig::get_https_api()
|
||||
{
|
||||
SrsConfDirective* conf = root->get("http_api");
|
||||
|
|
|
@ -1021,6 +1021,12 @@ public:
|
|||
virtual bool get_raw_api_allow_query();
|
||||
// Whether allow rpc update.
|
||||
virtual bool get_raw_api_allow_update();
|
||||
// Whether http api auth enabled.
|
||||
virtual bool get_http_api_auth_enabled();
|
||||
// Get the http api auth username.
|
||||
virtual std::string get_http_api_auth_username();
|
||||
// Get the http api auth password.
|
||||
virtual std::string get_http_api_auth_password();
|
||||
// https api section
|
||||
private:
|
||||
SrsConfDirective* get_https_api();
|
||||
|
|
|
@ -54,7 +54,9 @@ ISrsHttpConnOwner::~ISrsHttpConnOwner()
|
|||
SrsHttpConn::SrsHttpConn(ISrsHttpConnOwner* handler, ISrsProtocolReadWriter* fd, ISrsHttpServeMux* m, string cip, int cport)
|
||||
{
|
||||
parser = new SrsHttpParser();
|
||||
cors = new SrsHttpCorsMux();
|
||||
auth = new SrsHttpAuthMux(m);
|
||||
cors = new SrsHttpCorsMux(auth);
|
||||
|
||||
http_mux = m;
|
||||
handler_ = handler;
|
||||
|
||||
|
@ -74,6 +76,7 @@ SrsHttpConn::~SrsHttpConn()
|
|||
|
||||
srs_freep(parser);
|
||||
srs_freep(cors);
|
||||
srs_freep(auth);
|
||||
|
||||
srs_freep(delta_);
|
||||
}
|
||||
|
@ -227,10 +230,10 @@ srs_error_t SrsHttpConn::process_request(ISrsHttpResponseWriter* w, ISrsHttpMess
|
|||
|
||||
srs_trace("HTTP #%d %s:%d %s %s, content-length=%" PRId64 "", rid, ip.c_str(), port,
|
||||
r->method_str().c_str(), r->url().c_str(), r->content_length());
|
||||
|
||||
// use cors server mux to serve http request, which will proxy to http_remux.
|
||||
|
||||
// proxy to cors-->auth-->http_remux.
|
||||
if ((err = cors->serve_http(w, r)) != srs_success) {
|
||||
return srs_error_wrap(err, "mux serve");
|
||||
return srs_error_wrap(err, "cors serve");
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -256,14 +259,27 @@ srs_error_t SrsHttpConn::set_crossdomain_enabled(bool v)
|
|||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// initialize the cors, which will proxy to mux.
|
||||
if ((err = cors->initialize(http_mux, v)) != srs_success) {
|
||||
if ((err = cors->initialize(v)) != srs_success) {
|
||||
return srs_error_wrap(err, "init cors");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpConn::set_auth_enabled(bool auth_enabled)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
// initialize the auth, which will proxy to mux.
|
||||
if ((err = auth->initialize(auth_enabled,
|
||||
_srs_config->get_http_api_auth_username(),
|
||||
_srs_config->get_http_api_auth_password())) != srs_success) {
|
||||
return srs_error_wrap(err, "init auth");
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpConn::set_jsonp(bool v)
|
||||
{
|
||||
parser->set_jsonp(v);
|
||||
|
@ -451,6 +467,11 @@ srs_error_t SrsHttpxConn::start()
|
|||
return srs_error_wrap(err, "set cors=%d", v);
|
||||
}
|
||||
|
||||
bool auth_enabled = _srs_config->get_http_api_auth_enabled();
|
||||
if ((err = conn->set_auth_enabled(auth_enabled)) != srs_success) {
|
||||
return srs_error_wrap(err, "set auth");
|
||||
}
|
||||
|
||||
return conn->start();
|
||||
}
|
||||
|
||||
|
|
|
@ -67,6 +67,7 @@ protected:
|
|||
SrsHttpParser* parser;
|
||||
ISrsHttpServeMux* http_mux;
|
||||
SrsHttpCorsMux* cors;
|
||||
SrsHttpAuthMux* auth;
|
||||
ISrsHttpConnOwner* handler_;
|
||||
protected:
|
||||
ISrsProtocolReadWriter* skt;
|
||||
|
@ -111,6 +112,8 @@ public:
|
|||
virtual srs_error_t pull();
|
||||
// Whether enable the CORS(cross-domain).
|
||||
virtual srs_error_t set_crossdomain_enabled(bool v);
|
||||
// Whether enable the Auth.
|
||||
virtual srs_error_t set_auth_enabled(bool auth_enabled);
|
||||
// Whether enable the JSONP.
|
||||
virtual srs_error_t set_jsonp(bool v);
|
||||
// Interface ISrsConnection.
|
||||
|
|
|
@ -9,6 +9,6 @@
|
|||
|
||||
#define VERSION_MAJOR 5
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_REVISION 151
|
||||
#define VERSION_REVISION 152
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,6 +9,6 @@
|
|||
|
||||
#define VERSION_MAJOR 6
|
||||
#define VERSION_MINOR 0
|
||||
#define VERSION_REVISION 39
|
||||
#define VERSION_REVISION 40
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,6 +24,9 @@ using namespace std;
|
|||
// @see ISrsHttpMessage._http_ts_send_buffer
|
||||
#define SRS_HTTP_TS_SEND_BUFFER_SIZE 4096
|
||||
|
||||
#define SRS_HTTP_AUTH_SCHEME_BASIC "Basic"
|
||||
#define SRS_HTTP_AUTH_PREFIX_BASIC SRS_HTTP_AUTH_SCHEME_BASIC " "
|
||||
|
||||
// get the status text of code.
|
||||
string srs_generate_http_status_text(int status)
|
||||
{
|
||||
|
@ -861,22 +864,20 @@ bool SrsHttpServeMux::path_match(string pattern, string path)
|
|||
return false;
|
||||
}
|
||||
|
||||
SrsHttpCorsMux::SrsHttpCorsMux()
|
||||
SrsHttpCorsMux::SrsHttpCorsMux(ISrsHttpHandler* h)
|
||||
{
|
||||
next = NULL;
|
||||
enabled = false;
|
||||
required = false;
|
||||
next_ = h;
|
||||
}
|
||||
|
||||
SrsHttpCorsMux::~SrsHttpCorsMux()
|
||||
{
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpCorsMux::initialize(ISrsHttpServeMux* worker, bool cros_enabled)
|
||||
srs_error_t SrsHttpCorsMux::initialize(bool cros_enabled)
|
||||
{
|
||||
next = worker;
|
||||
enabled = cros_enabled;
|
||||
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
|
@ -920,9 +921,89 @@ srs_error_t SrsHttpCorsMux::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessag
|
|||
}
|
||||
return w->final_request();
|
||||
}
|
||||
|
||||
srs_assert(next);
|
||||
return next->serve_http(w, r);
|
||||
|
||||
return next_->serve_http(w, r);
|
||||
}
|
||||
|
||||
SrsHttpAuthMux::SrsHttpAuthMux(ISrsHttpHandler* h)
|
||||
{
|
||||
next_ = h;
|
||||
enabled_ = false;
|
||||
}
|
||||
|
||||
SrsHttpAuthMux::~SrsHttpAuthMux()
|
||||
{
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpAuthMux::initialize(bool enabled, std::string username, std::string password)
|
||||
{
|
||||
enabled_ = enabled;
|
||||
username_ = username;
|
||||
password_ = password;
|
||||
|
||||
return srs_success;
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpAuthMux::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
srs_error_t err;
|
||||
if ((err = do_auth(w, r)) != srs_success) {
|
||||
srs_error("do_auth %s", srs_error_desc(err).c_str());
|
||||
srs_freep(err);
|
||||
w->write_header(SRS_CONSTS_HTTP_Unauthorized);
|
||||
return w->final_request();
|
||||
}
|
||||
|
||||
srs_assert(next_);
|
||||
return next_->serve_http(w, r);
|
||||
}
|
||||
|
||||
srs_error_t SrsHttpAuthMux::do_auth(ISrsHttpResponseWriter* w, ISrsHttpMessage* r)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (!enabled_) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// We only apply for api starts with /api/ for HTTP API.
|
||||
// We don't apply for other apis such as /rtc/, for which we use http callback.
|
||||
if (r->path().find("/api/") == std::string::npos) {
|
||||
return err;
|
||||
}
|
||||
|
||||
std::string auth = r->header()->get("Authorization");
|
||||
if (auth.empty()) {
|
||||
w->header()->set("WWW-Authenticate", SRS_HTTP_AUTH_SCHEME_BASIC);
|
||||
return srs_error_new(SRS_CONSTS_HTTP_Unauthorized, "empty Authorization");
|
||||
}
|
||||
|
||||
if (!srs_string_contains(auth, SRS_HTTP_AUTH_PREFIX_BASIC)) {
|
||||
return srs_error_new(SRS_CONSTS_HTTP_Unauthorized, "invalid auth %s, should start with %s", auth.c_str(), SRS_HTTP_AUTH_PREFIX_BASIC);
|
||||
}
|
||||
|
||||
std::string token = srs_erase_first_substr(auth, SRS_HTTP_AUTH_PREFIX_BASIC);
|
||||
if (token.empty()) {
|
||||
return srs_error_new(SRS_CONSTS_HTTP_Unauthorized, "empty token from auth %s", auth.c_str());
|
||||
}
|
||||
|
||||
std::string plaintext;
|
||||
if ((err = srs_av_base64_decode(token, plaintext)) != srs_success) {
|
||||
return srs_error_wrap(err, "decode token %s", token.c_str());
|
||||
}
|
||||
|
||||
// The token format must be username:password
|
||||
std::vector<std::string> user_pwd = srs_string_split(plaintext, ":");
|
||||
if (user_pwd.size() != 2) {
|
||||
return srs_error_new(SRS_CONSTS_HTTP_Unauthorized, "invalid token %s", plaintext.c_str());
|
||||
}
|
||||
|
||||
if (username_ != user_pwd[0] || password_ != user_pwd[1]) {
|
||||
w->header()->set("WWW-Authenticate", SRS_HTTP_AUTH_SCHEME_BASIC);
|
||||
return srs_error_new(SRS_CONSTS_HTTP_Unauthorized, "invalid token %s:%s", user_pwd[0].c_str(), user_pwd[1].c_str());
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
ISrsHttpMessage::ISrsHttpMessage()
|
||||
|
|
|
@ -482,24 +482,46 @@ private:
|
|||
virtual bool path_match(std::string pattern, std::string path);
|
||||
};
|
||||
|
||||
// The filter http mux, directly serve the http CORS requests,
|
||||
// while proxy to the worker mux for services.
|
||||
// The filter http mux, directly serve the http CORS requests
|
||||
class SrsHttpCorsMux : public ISrsHttpHandler
|
||||
{
|
||||
private:
|
||||
bool required;
|
||||
bool enabled;
|
||||
ISrsHttpServeMux* next;
|
||||
ISrsHttpHandler* next_;
|
||||
public:
|
||||
SrsHttpCorsMux();
|
||||
SrsHttpCorsMux(ISrsHttpHandler* h);
|
||||
virtual ~SrsHttpCorsMux();
|
||||
public:
|
||||
virtual srs_error_t initialize(ISrsHttpServeMux* worker, bool cros_enabled);
|
||||
virtual srs_error_t initialize(bool cros_enabled);
|
||||
// Interface ISrsHttpServeMux
|
||||
public:
|
||||
virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
// The filter http mux, directly serve the http AUTH requests,
|
||||
// while proxy to the worker mux for services.
|
||||
// @see https://www.rfc-editor.org/rfc/rfc7617
|
||||
// @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticate
|
||||
class SrsHttpAuthMux : public ISrsHttpHandler
|
||||
{
|
||||
private:
|
||||
bool enabled_;
|
||||
std::string username_;
|
||||
std::string password_;
|
||||
ISrsHttpHandler* next_;
|
||||
public:
|
||||
SrsHttpAuthMux(ISrsHttpHandler* h);
|
||||
virtual ~SrsHttpAuthMux();
|
||||
public:
|
||||
virtual srs_error_t initialize(bool enabled, std::string username, std::string password);
|
||||
// Interface ISrsHttpServeMux
|
||||
public:
|
||||
virtual srs_error_t serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
private:
|
||||
virtual srs_error_t do_auth(ISrsHttpResponseWriter* w, ISrsHttpMessage* r);
|
||||
};
|
||||
|
||||
// A Request represents an HTTP request received by a server
|
||||
// or to be sent by a client.
|
||||
//
|
||||
|
|
|
@ -3639,7 +3639,7 @@ VOID TEST(ConfigMainTest, CheckVhostConfig5)
|
|||
|
||||
if (true) {
|
||||
MockSrsConfig conf;
|
||||
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "http_api{enabled on;listen xxx;crossdomain off;raw_api {enabled on;allow_reload on;allow_query on;allow_update on;}}"));
|
||||
HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "http_api{enabled on;listen xxx;crossdomain off;auth {enabled on;username admin;password 123456;}raw_api {enabled on;allow_reload on;allow_query on;allow_update on;}}"));
|
||||
EXPECT_TRUE(conf.get_http_api_enabled());
|
||||
EXPECT_STREQ("xxx", conf.get_http_api_listen().c_str());
|
||||
EXPECT_FALSE(conf.get_http_api_crossdomain());
|
||||
|
@ -3647,6 +3647,9 @@ VOID TEST(ConfigMainTest, CheckVhostConfig5)
|
|||
EXPECT_TRUE(conf.get_raw_api_allow_reload());
|
||||
EXPECT_FALSE(conf.get_raw_api_allow_query()); // Always disabled
|
||||
EXPECT_FALSE(conf.get_raw_api_allow_update()); // Always disabled
|
||||
EXPECT_TRUE(conf.get_http_api_auth_enabled());
|
||||
EXPECT_STREQ("admin", conf.get_http_api_auth_username().c_str());
|
||||
EXPECT_STREQ("123456", conf.get_http_api_auth_password().c_str());
|
||||
}
|
||||
|
||||
if (true) {
|
||||
|
@ -4112,6 +4115,15 @@ VOID TEST(ConfigEnvTest, CheckEnvValuesHttpApi)
|
|||
|
||||
SrsSetEnvConfig(http_api_crossdomain, "SRS_HTTP_API_CROSSDOMAIN", "off");
|
||||
EXPECT_FALSE(conf.get_http_api_crossdomain());
|
||||
|
||||
SrsSetEnvConfig(http_api_auth_enabled, "SRS_HTTP_API_AUTH_ENABLED", "on");
|
||||
EXPECT_TRUE(conf.get_http_api_auth_enabled());
|
||||
|
||||
SrsSetEnvConfig(http_api_auth_username, "SRS_HTTP_API_AUTH_USERNAME", "admin");
|
||||
EXPECT_STREQ("admin", conf.get_http_api_auth_username().c_str());
|
||||
|
||||
SrsSetEnvConfig(http_api_auth_password, "SRS_HTTP_API_AUTH_PASSWORD", "123456");
|
||||
EXPECT_STREQ("123456", conf.get_http_api_auth_password().c_str());
|
||||
}
|
||||
|
||||
if (true) {
|
||||
|
|
|
@ -1059,11 +1059,10 @@ VOID TEST(ProtocolHTTPTest, HTTPServerMuxerCORS)
|
|||
r.set_basic(HTTP_REQUEST, HTTP_POST, (http_status)200, -1);
|
||||
HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false));
|
||||
|
||||
SrsHttpCorsMux cs;
|
||||
HELPER_ASSERT_SUCCESS(cs.initialize(&s, true));
|
||||
SrsHttpCorsMux cs(&s);
|
||||
HELPER_ASSERT_SUCCESS(cs.initialize(true));
|
||||
|
||||
HELPER_ASSERT_SUCCESS(cs.serve_http(&w, &r));
|
||||
__MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w);
|
||||
}
|
||||
|
||||
// If CORS enabled, response OPTIONS with ok
|
||||
|
@ -1079,8 +1078,8 @@ VOID TEST(ProtocolHTTPTest, HTTPServerMuxerCORS)
|
|||
r.set_basic(HTTP_REQUEST, HTTP_OPTIONS, (http_status)200, -1);
|
||||
HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false));
|
||||
|
||||
SrsHttpCorsMux cs;
|
||||
HELPER_ASSERT_SUCCESS(cs.initialize(&s, true));
|
||||
SrsHttpCorsMux cs(&s);
|
||||
HELPER_ASSERT_SUCCESS(cs.initialize(true));
|
||||
|
||||
HELPER_ASSERT_SUCCESS(cs.serve_http(&w, &r));
|
||||
__MOCK_HTTP_EXPECT_STREQ(200, "", w);
|
||||
|
@ -1099,11 +1098,10 @@ VOID TEST(ProtocolHTTPTest, HTTPServerMuxerCORS)
|
|||
r.set_basic(HTTP_REQUEST, HTTP_POST, (http_status)200, -1);
|
||||
HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false));
|
||||
|
||||
SrsHttpCorsMux cs;
|
||||
HELPER_ASSERT_SUCCESS(cs.initialize(&s, false));
|
||||
SrsHttpCorsMux cs(&s);
|
||||
HELPER_ASSERT_SUCCESS(cs.initialize(false));
|
||||
|
||||
HELPER_ASSERT_SUCCESS(cs.serve_http(&w, &r));
|
||||
__MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w);
|
||||
}
|
||||
|
||||
// If CORS not enabled, response error for options.
|
||||
|
@ -1119,8 +1117,8 @@ VOID TEST(ProtocolHTTPTest, HTTPServerMuxerCORS)
|
|||
r.set_basic(HTTP_REQUEST, HTTP_OPTIONS, (http_status)200, -1);
|
||||
HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false));
|
||||
|
||||
SrsHttpCorsMux cs;
|
||||
HELPER_ASSERT_SUCCESS(cs.initialize(&s, false));
|
||||
SrsHttpCorsMux cs(&s);
|
||||
HELPER_ASSERT_SUCCESS(cs.initialize(false));
|
||||
|
||||
HELPER_ASSERT_SUCCESS(cs.serve_http(&w, &r));
|
||||
__MOCK_HTTP_EXPECT_STREQ(405, "", w);
|
||||
|
@ -1137,10 +1135,253 @@ VOID TEST(ProtocolHTTPTest, HTTPServerMuxerCORS)
|
|||
SrsHttpMessage r(NULL, NULL);
|
||||
HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false));
|
||||
|
||||
SrsHttpCorsMux cs;
|
||||
HELPER_ASSERT_SUCCESS(cs.initialize(&s, true));
|
||||
SrsHttpCorsMux cs(&s);
|
||||
HELPER_ASSERT_SUCCESS(cs.initialize(true));
|
||||
|
||||
HELPER_ASSERT_SUCCESS(cs.serve_http(&w, &r));
|
||||
}
|
||||
}
|
||||
|
||||
VOID TEST(ProtocolHTTPTest, HTTPServerMuxerAuth)
|
||||
{
|
||||
srs_error_t err;
|
||||
|
||||
if (true) {
|
||||
SrsHttpServeMux s;
|
||||
HELPER_ASSERT_SUCCESS(s.initialize());
|
||||
|
||||
MockHttpHandler* hroot = new MockHttpHandler("Hello, world!");
|
||||
HELPER_ASSERT_SUCCESS(s.handle("/", hroot));
|
||||
|
||||
MockResponseWriter w;
|
||||
SrsHttpMessage r(NULL, NULL);
|
||||
r.set_basic(HTTP_REQUEST, HTTP_POST, (http_status)200, -1);
|
||||
|
||||
SrsHttpHeader h ;
|
||||
h.set("Authorization", "Basic YWRtaW46YWRtaW4="); // admin:admin
|
||||
r.set_header(&h, false);
|
||||
|
||||
HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false));
|
||||
|
||||
SrsHttpAuthMux auth(&s);
|
||||
HELPER_ASSERT_SUCCESS(auth.initialize(true, "admin", "admin"));
|
||||
|
||||
HELPER_ASSERT_SUCCESS(auth.serve_http(&w, &r));
|
||||
__MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w);
|
||||
}
|
||||
|
||||
// incorrect token
|
||||
if (true) {
|
||||
SrsHttpServeMux s;
|
||||
HELPER_ASSERT_SUCCESS(s.initialize());
|
||||
|
||||
MockHttpHandler* hroot = new MockHttpHandler("Hello, world!");
|
||||
HELPER_ASSERT_SUCCESS(s.handle("/", hroot));
|
||||
|
||||
MockResponseWriter w;
|
||||
SrsHttpMessage r(NULL, NULL);
|
||||
r.set_basic(HTTP_REQUEST, HTTP_POST, (http_status)200, -1);
|
||||
|
||||
SrsHttpHeader h ;
|
||||
h.set("Authorization", "Basic YWRtaW46YWRtaW4="); // admin:admin
|
||||
r.set_header(&h, false);
|
||||
|
||||
HELPER_ASSERT_SUCCESS(r.set_url("/api/v1/clients/", false));
|
||||
|
||||
SrsHttpAuthMux auth(&s);
|
||||
HELPER_ASSERT_SUCCESS(auth.initialize(true, "admin", "123456"));
|
||||
|
||||
HELPER_ASSERT_SUCCESS(auth.serve_http(&w, &r));
|
||||
EXPECT_EQ(401, w.w->status);
|
||||
}
|
||||
|
||||
// incorrect token, duplicate Basic
|
||||
if (true) {
|
||||
SrsHttpServeMux s;
|
||||
HELPER_ASSERT_SUCCESS(s.initialize());
|
||||
|
||||
MockHttpHandler* hroot = new MockHttpHandler("Hello, world!");
|
||||
HELPER_ASSERT_SUCCESS(s.handle("/", hroot));
|
||||
|
||||
MockResponseWriter w;
|
||||
SrsHttpMessage r(NULL, NULL);
|
||||
r.set_basic(HTTP_REQUEST, HTTP_POST, (http_status)200, -1);
|
||||
|
||||
SrsHttpHeader h ;
|
||||
h.set("Authorization", "Basic BasicYWRtaW46YWRtaW4="); // duplicate 'Basic'
|
||||
r.set_header(&h, false);
|
||||
|
||||
HELPER_ASSERT_SUCCESS(r.set_url("/api/v1/clients/", false));
|
||||
|
||||
SrsHttpAuthMux auth(&s);
|
||||
HELPER_ASSERT_SUCCESS(auth.initialize(true, "admin", "admin"));
|
||||
|
||||
HELPER_ASSERT_SUCCESS(auth.serve_http(&w, &r));
|
||||
EXPECT_EQ(401, w.w->status);
|
||||
}
|
||||
|
||||
// Authorization NOT start with 'Basic '
|
||||
if (true) {
|
||||
SrsHttpServeMux s;
|
||||
HELPER_ASSERT_SUCCESS(s.initialize());
|
||||
|
||||
MockHttpHandler* hroot = new MockHttpHandler("Hello, world!");
|
||||
HELPER_ASSERT_SUCCESS(s.handle("/", hroot));
|
||||
|
||||
MockResponseWriter w;
|
||||
SrsHttpMessage r(NULL, NULL);
|
||||
r.set_basic(HTTP_REQUEST, HTTP_POST, (http_status)200, -1);
|
||||
|
||||
SrsHttpHeader h ;
|
||||
h.set("Authorization", "YWRtaW46YWRtaW4="); // admin:admin
|
||||
r.set_header(&h, false);
|
||||
|
||||
HELPER_ASSERT_SUCCESS(r.set_url("/api/v1/clients/", false));
|
||||
|
||||
SrsHttpAuthMux auth(&s);
|
||||
HELPER_ASSERT_SUCCESS(auth.initialize(true, "admin", "admin"));
|
||||
|
||||
HELPER_ASSERT_SUCCESS(auth.serve_http(&w, &r));
|
||||
EXPECT_EQ(401, w.w->status);
|
||||
}
|
||||
|
||||
// NOT base64
|
||||
if (true) {
|
||||
SrsHttpServeMux s;
|
||||
HELPER_ASSERT_SUCCESS(s.initialize());
|
||||
|
||||
MockHttpHandler* hroot = new MockHttpHandler("Hello, world!");
|
||||
HELPER_ASSERT_SUCCESS(s.handle("/", hroot));
|
||||
|
||||
MockResponseWriter w;
|
||||
SrsHttpMessage r(NULL, NULL);
|
||||
r.set_basic(HTTP_REQUEST, HTTP_POST, (http_status)200, -1);
|
||||
|
||||
SrsHttpHeader h ;
|
||||
h.set("Authorization", "Basic admin:admin"); // admin:admin
|
||||
r.set_header(&h, false);
|
||||
|
||||
HELPER_ASSERT_SUCCESS(r.set_url("/api/v1/clients/", false));
|
||||
|
||||
SrsHttpAuthMux auth(&s);
|
||||
HELPER_ASSERT_SUCCESS(auth.initialize(true, "admin", "admin"));
|
||||
|
||||
HELPER_ASSERT_SUCCESS(auth.serve_http(&w, &r));
|
||||
EXPECT_EQ(401, w.w->status);
|
||||
}
|
||||
|
||||
// empty Authorization
|
||||
if (true) {
|
||||
SrsHttpServeMux s;
|
||||
HELPER_ASSERT_SUCCESS(s.initialize());
|
||||
|
||||
MockHttpHandler* hroot = new MockHttpHandler("Hello, world!");
|
||||
HELPER_ASSERT_SUCCESS(s.handle("/", hroot));
|
||||
|
||||
MockResponseWriter w;
|
||||
SrsHttpMessage r(NULL, NULL);
|
||||
r.set_basic(HTTP_REQUEST, HTTP_POST, (http_status)200, -1);
|
||||
HELPER_ASSERT_SUCCESS(r.set_url("/api/v1/clients/", false));
|
||||
|
||||
SrsHttpAuthMux auth(&s);
|
||||
HELPER_ASSERT_SUCCESS(auth.initialize(true, "admin", "admin"));
|
||||
|
||||
HELPER_ASSERT_SUCCESS(auth.serve_http(&w, &r));
|
||||
EXPECT_EQ(401, w.w->status);
|
||||
}
|
||||
|
||||
// auth disabled, response with 200 ok, even though empty Authorization
|
||||
if (true) {
|
||||
SrsHttpServeMux s;
|
||||
HELPER_ASSERT_SUCCESS(s.initialize());
|
||||
|
||||
MockHttpHandler* hroot = new MockHttpHandler("Hello, world!");
|
||||
HELPER_ASSERT_SUCCESS(s.handle("/", hroot));
|
||||
|
||||
MockResponseWriter w;
|
||||
SrsHttpMessage r(NULL, NULL);
|
||||
r.set_basic(HTTP_REQUEST, HTTP_POST, (http_status)200, -1);
|
||||
HELPER_ASSERT_SUCCESS(r.set_url("/api/v1/clients/", false));
|
||||
|
||||
SrsHttpAuthMux auth(&s);
|
||||
HELPER_ASSERT_SUCCESS(auth.initialize(false, "admin", "admin"));
|
||||
|
||||
HELPER_ASSERT_SUCCESS(auth.serve_http(&w, &r));
|
||||
__MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w);
|
||||
}
|
||||
|
||||
// auth disabled, response with 200 ok, even though wrong token
|
||||
if (true) {
|
||||
SrsHttpServeMux s;
|
||||
HELPER_ASSERT_SUCCESS(s.initialize());
|
||||
|
||||
MockHttpHandler* hroot = new MockHttpHandler("Hello, world!");
|
||||
HELPER_ASSERT_SUCCESS(s.handle("/", hroot));
|
||||
|
||||
MockResponseWriter w;
|
||||
SrsHttpMessage r(NULL, NULL);
|
||||
r.set_basic(HTTP_REQUEST, HTTP_POST, (http_status)200, -1);
|
||||
|
||||
SrsHttpHeader h ;
|
||||
h.set("Authorization", "Basic YWRtaW46YWRtaW4="); // admin:admin
|
||||
r.set_header(&h, false);
|
||||
|
||||
HELPER_ASSERT_SUCCESS(r.set_url("/api/v1/clients/", false));
|
||||
|
||||
SrsHttpAuthMux auth(&s);
|
||||
HELPER_ASSERT_SUCCESS(auth.initialize(false, "admin", "123456"));
|
||||
|
||||
HELPER_ASSERT_SUCCESS(auth.serve_http(&w, &r));
|
||||
__MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w);
|
||||
}
|
||||
|
||||
// always response with 200 ok, for /rtc/*/
|
||||
if (true) {
|
||||
SrsHttpServeMux s;
|
||||
HELPER_ASSERT_SUCCESS(s.initialize());
|
||||
|
||||
MockHttpHandler* hroot = new MockHttpHandler("Hello, world!");
|
||||
HELPER_ASSERT_SUCCESS(s.handle("/", hroot));
|
||||
|
||||
MockResponseWriter w;
|
||||
SrsHttpMessage r(NULL, NULL);
|
||||
r.set_basic(HTTP_REQUEST, HTTP_POST, (http_status)200, -1);
|
||||
|
||||
SrsHttpHeader h ;
|
||||
h.set("Authorization", "Basic YWRtaW46YWRtaW4="); // admin:admin
|
||||
r.set_header(&h, false);
|
||||
|
||||
HELPER_ASSERT_SUCCESS(r.set_url("/rtc/play/", false));
|
||||
|
||||
SrsHttpAuthMux auth(&s);
|
||||
HELPER_ASSERT_SUCCESS(auth.initialize(false, "admin", "123456"));
|
||||
|
||||
HELPER_ASSERT_SUCCESS(auth.serve_http(&w, &r));
|
||||
__MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w);
|
||||
}
|
||||
|
||||
// always response with 200 ok, for /rtc/*/
|
||||
if (true) {
|
||||
SrsHttpServeMux s;
|
||||
HELPER_ASSERT_SUCCESS(s.initialize());
|
||||
|
||||
MockHttpHandler* hroot = new MockHttpHandler("Hello, world!");
|
||||
HELPER_ASSERT_SUCCESS(s.handle("/", hroot));
|
||||
|
||||
MockResponseWriter w;
|
||||
SrsHttpMessage r(NULL, NULL);
|
||||
r.set_basic(HTTP_REQUEST, HTTP_POST, (http_status)200, -1);
|
||||
|
||||
SrsHttpHeader h ;
|
||||
h.set("Authorization", "Basic YWRtaW46YWRtaW4="); // admin:admin
|
||||
r.set_header(&h, false);
|
||||
|
||||
HELPER_ASSERT_SUCCESS(r.set_url("/index.html", false));
|
||||
|
||||
SrsHttpAuthMux auth(&s);
|
||||
HELPER_ASSERT_SUCCESS(auth.initialize(false, "admin", "123456"));
|
||||
|
||||
HELPER_ASSERT_SUCCESS(auth.serve_http(&w, &r));
|
||||
__MOCK_HTTP_EXPECT_STREQ(200, "Hello, world!", w);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6209,4 +6209,33 @@ VOID TEST(KernelUtilityTest, CoverCheckIPAddrValid)
|
|||
ASSERT_FALSE(srs_check_ip_addr_valid("2001:0db8:85a3:0:0:8A2E:0370:7334:"));
|
||||
#endif
|
||||
ASSERT_FALSE(srs_check_ip_addr_valid("1e1.4.5.6"));
|
||||
}
|
||||
|
||||
VOID TEST(KernelUtilityTest, Base64Decode)
|
||||
{
|
||||
srs_error_t err = srs_success;
|
||||
|
||||
if (true) {
|
||||
string plaintext;
|
||||
HELPER_EXPECT_SUCCESS(srs_av_base64_decode("YWRtaW46YWRtaW4=", plaintext));
|
||||
EXPECT_STREQ("admin:admin", plaintext.c_str());
|
||||
}
|
||||
|
||||
if (true) {
|
||||
string plaintext;
|
||||
HELPER_EXPECT_SUCCESS(srs_av_base64_decode("YWRtaW46MTIzNDU2", plaintext));
|
||||
EXPECT_STREQ("admin:123456", plaintext.c_str());
|
||||
}
|
||||
|
||||
if (true) {
|
||||
string plaintext;
|
||||
HELPER_EXPECT_SUCCESS(srs_av_base64_decode("YWRtaW46MTIzNDU2", plaintext));
|
||||
EXPECT_STRNE("admin:admin", plaintext.c_str());
|
||||
}
|
||||
|
||||
if (true) {
|
||||
string plaintext;
|
||||
HELPER_EXPECT_FAILED(srs_av_base64_decode("YWRtaW46YWRtaW", plaintext));
|
||||
EXPECT_STRNE("admin:admin", plaintext.c_str());
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue