mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +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
				
			
		|  | @ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue