public bool TryAuthorize(RavenBaseApiController controller, out HttpResponseMessage msg) { var requestUrl = controller.GetRequestUrl(); if (NeverSecret.IsNeverSecretUrl(requestUrl)) { msg = controller.GetEmptyMessage(); return(true); } //CORS pre-flight (ignore creds if using cors). if (Settings.AccessControlAllowOrigin.Count > 0 && controller.InnerRequest.Method.Method == "OPTIONS") { msg = controller.GetEmptyMessage(); return(true); } var oneTimeToken = controller.GetHeader("Single-Use-Auth-Token"); if (string.IsNullOrEmpty(oneTimeToken) == false) { return(TryAuthorizeSingleUseAuthToken(controller, oneTimeToken, out msg)); } var authHeader = controller.GetHeader("Authorization"); var hasApiKey = "True".Equals(controller.GetHeader("Has-Api-Key"), StringComparison.CurrentCultureIgnoreCase); var hasOAuthTokenInCookie = controller.HasCookie("OAuth-Token"); if (hasApiKey || hasOAuthTokenInCookie || string.IsNullOrEmpty(authHeader) == false && authHeader.StartsWith("Bearer ")) { return(oAuthRequestAuthorizer.TryAuthorize(controller, hasApiKey, IgnoreDb.Urls.Contains(requestUrl), out msg)); } return(windowsRequestAuthorizer.TryAuthorize(controller, IgnoreDb.Urls.Contains(requestUrl), out msg)); }
private PrincipalWithDatabaseAccess UpdateUserPrincipal(RavenBaseApiController controller, List <ResourceAccess> databaseAccessLists) { var access = controller.User as PrincipalWithDatabaseAccess; if (access != null) { return(access); } var user = new PrincipalWithDatabaseAccess((WindowsPrincipal)controller.User); foreach (var databaseAccess in databaseAccessLists) { if (databaseAccess.Admin) { user.AdminDatabases.Add(databaseAccess.TenantId); } else if (databaseAccess.ReadOnly) { user.ReadOnlyDatabases.Add(databaseAccess.TenantId); } else { user.ReadWriteDatabases.Add(databaseAccess.TenantId); } } controller.User = user; Thread.CurrentPrincipal = user; return(user); }
HttpResponseMessage WriteAuthorizationChallenge(RavenBaseApiController controller, int statusCode, string error, string errorDescription) { var msg = controller.GetEmptyMessage(); var systemConfiguration = controller.SystemConfiguration; if (string.IsNullOrEmpty(systemConfiguration.OAuthTokenServer) == false) { if (systemConfiguration.UseDefaultOAuthTokenServer == false) { controller.AddHeader("OAuth-Source", systemConfiguration.OAuthTokenServer, msg); } else { controller.AddHeader("OAuth-Source", new UriBuilder(systemConfiguration.OAuthTokenServer) { Scheme = controller.InnerRequest.RequestUri.Scheme, Host = controller.InnerRequest.RequestUri.Host, Port = controller.InnerRequest.RequestUri.Port, }.Uri.ToString(), msg); } } msg.StatusCode = (HttpStatusCode)statusCode; msg.Headers.Add("WWW-Authenticate", string.Format("Bearer realm=\"Raven\", error=\"{0}\",error_description=\"{1}\"", error, errorDescription)); msg.Headers.Add("Access-Control-Expose-Headers", "WWW-Authenticate, OAuth-Source"); return(msg); }
public bool TryAuthorize(RavenBaseApiController controller, out HttpResponseMessage msg) { var requestUrl = controller.GetRequestUrl(); if (NeverSecret.IsNeverSecretUrl(requestUrl)) { msg = controller.GetEmptyMessage(); return true; } //CORS pre-flight (ignore creds if using cors). if (!String.IsNullOrEmpty(Settings.AccessControlAllowOrigin) && controller.InnerRequest.Method.Method == "OPTIONS") { msg = controller.GetEmptyMessage(); return true; } var oneTimeToken = controller.GetHeader("Single-Use-Auth-Token"); if (string.IsNullOrEmpty(oneTimeToken) == false) { return TryAuthorizeSingleUseAuthToken(controller, oneTimeToken, out msg); } var authHeader = controller.GetHeader("Authorization"); var hasApiKey = "True".Equals(controller.GetHeader("Has-Api-Key"), StringComparison.CurrentCultureIgnoreCase); var hasOAuthTokenInCookie = controller.HasCookie("OAuth-Token"); if (hasApiKey || hasOAuthTokenInCookie || string.IsNullOrEmpty(authHeader) == false && authHeader.StartsWith("Bearer ")) { return oAuthRequestAuthorizer.TryAuthorize(controller, hasApiKey, IgnoreDb.Urls.Contains(requestUrl), out msg); } return windowsRequestAuthorizer.TryAuthorize(controller, IgnoreDb.Urls.Contains(requestUrl), out msg); }
private void LogHttpRequestStats(RavenBaseApiController controller, LogHttpRequestStatsParams logHttpRequestStatsParams, string databaseName, long curReq) { if (Logger.IsDebugEnabled == false) { return; } if (controller is StudioController || controller is HardRouteController || controller is SilverlightController) { return; } var message = string.Format(CultureInfo.InvariantCulture, "Request #{0,4:#,0}: {1,-7} - {2,5:#,0} ms - {5,-10} - {3} - {4}", curReq, logHttpRequestStatsParams.HttpMethod, logHttpRequestStatsParams.Stopwatch.ElapsedMilliseconds, logHttpRequestStatsParams.ResponseStatusCode, logHttpRequestStatsParams.RequestUri, databaseName); Logger.Debug(message); if (string.IsNullOrWhiteSpace(logHttpRequestStatsParams.CustomInfo) == false) { Logger.Debug(logHttpRequestStatsParams.CustomInfo); } }
private bool TryAuthorizeSingleUseAuthToken(RavenBaseApiController controller, string token, out HttpResponseMessage msg) { if (controller.WasAlreadyAuthorizedUsingSingleAuthToken) { msg = controller.GetEmptyMessage(); return(true); } object result; HttpStatusCode statusCode; IPrincipal user; var success = TryAuthorizeSingleUseAuthToken(token, controller.TenantName, out result, out statusCode, out user); controller.User = user; if (success == false) { msg = controller.GetMessageWithObject(result, statusCode); } else { msg = controller.GetEmptyMessage(); } controller.WasAlreadyAuthorizedUsingSingleAuthToken = success; return(success); }
private void LogHttpRequestStats(RavenBaseApiController controller, LogHttpRequestStatsParams logHttpRequestStatsParams, string databaseName, long curReq) { if (Logger.IsDebugEnabled == false) { return; } if (controller is StudioController || controller is HardRouteController || controller is SilverlightController) { return; } // we filter out requests for the UI because they fill the log with information // we probably don't care about them anyway. That said, we do output them if they take too // long. if (logHttpRequestStatsParams.Headers["Raven-Timer-Request"] == "true" && logHttpRequestStatsParams.Stopwatch.ElapsedMilliseconds <= 25) { return; } var message = string.Format(CultureInfo.InvariantCulture, "Request #{0,4:#,0}: {1,-7} - {2,5:#,0} ms - {5,-10} - {3} - {4}", curReq, logHttpRequestStatsParams.HttpMethod, logHttpRequestStatsParams.Stopwatch.ElapsedMilliseconds, logHttpRequestStatsParams.ResponseStatusCode, logHttpRequestStatsParams.RequestUri, databaseName); Logger.Debug(message); if (string.IsNullOrWhiteSpace(logHttpRequestStatsParams.CustomInfo) == false) { Logger.Debug(logHttpRequestStatsParams.CustomInfo); } }
public LogsPushContent(RavenBaseApiController controller) { Connected = true; Id = controller.GetQueryStringValue("id"); if (string.IsNullOrEmpty(Id)) throw new ArgumentException("Id is mandatory"); }
private bool TryCreateUser(RavenBaseApiController controller, string databaseName, out Func <HttpResponseMessage> onRejectingRequest) { var invalidUser = (controller.User == null || controller.User.Identity.IsAuthenticated == false); if (invalidUser) { onRejectingRequest = () => { var msg = ProvideDebugAuthInfo(controller, new { Reason = "User is null or not authenticated" }); controller.AddHeader("Raven-Required-Auth", "Windows", msg); if (string.IsNullOrEmpty(controller.SystemConfiguration.OAuthTokenServer) == false) { controller.AddHeader("OAuth-Source", controller.SystemConfiguration.OAuthTokenServer, msg); } msg.StatusCode = HttpStatusCode.Unauthorized; return(msg); }; return(false); } var dbUsersIsAllowedAccessTo = requiredUsers .Where(data => controller.User.Identity.Name.Equals(data.Name, StringComparison.InvariantCultureIgnoreCase)) .SelectMany(source => source.Databases) .Concat(requiredGroups.Where(data => controller.User.IsInRole(data.Name)).SelectMany(x => x.Databases)) .ToList(); var fsUsersIsAllowedAccessTo = requiredUsers .Where(data => controller.User.Identity.Name.Equals(data.Name, StringComparison.InvariantCultureIgnoreCase)) .SelectMany(source => source.FileSystems) .Concat(requiredGroups.Where(data => controller.User.IsInRole(data.Name)).SelectMany(x => x.FileSystems)) .ToList(); var user = UpdateUserPrincipal(controller, dbUsersIsAllowedAccessTo, fsUsersIsAllowedAccessTo); onRejectingRequest = () => { var msg = ProvideDebugAuthInfo(controller, new { user.Identity.Name, user.AdminDatabases, user.ReadOnlyDatabases, user.ReadWriteDatabases, user.ReadOnlyFileSystems, user.ReadWriteFileSystems, DatabaseName = databaseName }); msg.StatusCode = HttpStatusCode.Forbidden; throw new HttpResponseException(msg); }; return(true); }
public async Task <HttpResponseMessage> HandleActualRequest(RavenBaseApiController controller, HttpControllerContext controllerContext, Func <Task <HttpResponseMessage> > action, Func <HttpException, HttpResponseMessage> onHttpException) { HttpResponseMessage response = null; cancellationToken.ThrowIfCancellationRequested(); Stopwatch sw = Stopwatch.StartNew(); try { Interlocked.Increment(ref concurrentRequests); if (controller.SetupRequestToProperDatabase(this)) { if (controller.ResourceConfiguration.RejectClientsMode && controllerContext.Request.Headers.Contains(Constants.RavenClientVersion)) { response = new HttpResponseMessage(HttpStatusCode.ServiceUnavailable) { Content = new MultiGetSafeStringContent("This service is not accepting clients calls") }; } else { response = await action(); } } } catch (HttpException httpException) { response = onHttpException(httpException); } finally { Interlocked.Decrement(ref concurrentRequests); try { FinalizeRequestProcessing(controller, response, sw); } catch (Exception e) { var aggregateException = e as AggregateException; if (aggregateException != null) { e = aggregateException.ExtractSingleInnerException(); } Logger.ErrorException("Could not finalize request properly", e); } } return(response); }
public LogsPushContent(RavenBaseApiController controller) { Connected = true; Id = controller.GetQueryStringValue("id"); if (string.IsNullOrEmpty(Id)) { throw new ArgumentException("Id is mandatory"); } }
public IPrincipal GetUser(RavenBaseApiController controller) { Func <HttpResponseMessage> onRejectingRequest; var databaseName = controller.ResourceName ?? Constants.SystemDatabase; var userCreated = TryCreateUser(controller, databaseName, out onRejectingRequest); if (userCreated == false) { onRejectingRequest(); } return(userCreated ? controller.User : null); }
public async Task <HttpResponseMessage> HandleActualRequest(RavenBaseApiController controller, Func <Task <HttpResponseMessage> > action, Func <HttpException, HttpResponseMessage> onHttpException) { HttpResponseMessage response = null; cancellationToken.ThrowIfCancellationRequested(); Stopwatch sw = Stopwatch.StartNew(); try { Interlocked.Increment(ref concurrentRequests); if (IsWriteRequest(controller.InnerRequest)) { lastWriteRequest = SystemTime.UtcNow; } if (controller.SetupRequestToProperDatabase(this)) { response = await action(); } } catch (HttpException httpException) { response = onHttpException(httpException); } finally { Interlocked.Decrement(ref concurrentRequests); try { FinalizeRequestProcessing(controller, response, sw); } catch (Exception e) { var aggregateException = e as AggregateException; if (aggregateException != null) { e = aggregateException.ExtractSingleInnerException(); } Logger.ErrorException("Could not finalize request properly", e); } } return(response); }
public ChangesPushContent(RavenBaseApiController controller) { Connected = true; ResourceName = controller.TenantName; Id = controller.GetQueryStringValue("id"); if (string.IsNullOrEmpty(Id)) throw new ArgumentException("Id is mandatory"); long coolDownWithDataLossInMiliseconds = 0; long.TryParse(controller.GetQueryStringValue("coolDownWithDataLoss"), out coolDownWithDataLossInMiliseconds); CoolDownWithDataLossInMiliseconds = coolDownWithDataLossInMiliseconds; }
private void FinalizeRequestProcessing(RavenBaseApiController controller, HttpResponseMessage response, Stopwatch sw) { LogHttpRequestStatsParams logHttpRequestStatsParam = null; try { StringBuilder sb = null; if (controller.CustomRequestTraceInfo != null) { sb = new StringBuilder(); foreach (var action in controller.CustomRequestTraceInfo) { action(sb); sb.AppendLine(); } while (sb.Length > 0) { if (!char.IsWhiteSpace(sb[sb.Length - 1])) { break; } sb.Length--; } } logHttpRequestStatsParam = new LogHttpRequestStatsParams( sw, GetHeaders(controller.InnerHeaders), controller.InnerRequest.Method.Method, response != null ? (int)response.StatusCode : 500, controller.InnerRequest.RequestUri.ToString(), sb != null ? sb.ToString() : null ); } catch (Exception e) { Logger.WarnException("Could not gather information to log request stats", e); } if (logHttpRequestStatsParam == null || sw == null) { return; } sw.Stop(); controller.MarkRequestDuration(sw.ElapsedMilliseconds); LogHttpRequestStats(controller, logHttpRequestStatsParam, controller.TenantName); TraceRequest(logHttpRequestStatsParam, controller.TenantName); }
public ConnectionState For(string id, RavenBaseApiController controller = null) { return(connections.GetOrAdd(id, _ => { IEventsTransport eventsTransport = null; if (controller != null) { eventsTransport = new ChangesPushContent(controller); } var connectionState = new ConnectionState(eventsTransport); TimeSensitiveStore.Missing(id); return connectionState; })); }
public ChangesPushContent(RavenBaseApiController controller) { Connected = true; Id = controller.GetQueryStringValue("id"); if (string.IsNullOrEmpty(Id)) { throw new ArgumentException("Id is mandatory"); } long coolDownWithDataLossInMilisecods = 0; long.TryParse(controller.GetQueryStringValue("coolDownWithDataLoss"), out coolDownWithDataLossInMilisecods); CoolDownWithDataLossInMilisecods = coolDownWithDataLossInMilisecods; }
public static bool IsGetRequest(RavenBaseApiController controller) { switch (controller.InnerRequest.Method.Method) { case "GET": case "HEAD": return true; case "POST": var absolutePath = controller.InnerRequest.RequestUri.AbsolutePath; return absolutePath.EndsWith("/queries", StringComparison.Ordinal) || absolutePath.EndsWith("/multi_get", StringComparison.Ordinal) || absolutePath.EndsWith("/multi_get/", StringComparison.Ordinal); default: return false; } }
public ChangesPushContent(RavenBaseApiController controller) { Connected = true; ResourceName = controller.TenantName; Id = controller.GetQueryStringValue("id"); if (string.IsNullOrEmpty(Id)) { throw new ArgumentException("Id is mandatory"); } cancellationTokenSource = WebSocketTransportFactory.RavenGcCancellation; long coolDownWithDataLossInMiliseconds = 0; long.TryParse(controller.GetQueryStringValue("coolDownWithDataLoss"), out coolDownWithDataLossInMiliseconds); CoolDownWithDataLossInMiliseconds = coolDownWithDataLossInMiliseconds; }
// Cross-Origin Resource Sharing (CORS) is documented here: http://www.w3.org/TR/cors/ public void AddAccessControlHeaders(RavenBaseApiController controller, HttpResponseMessage msg) { var accessControlAllowOrigin = landlord.SystemConfiguration.AccessControlAllowOrigin; if (accessControlAllowOrigin.Count == 0) { return; } var originHeader = controller.GetHeader("Origin"); if (originHeader == null || originHeader.Contains(controller.InnerRequest.Headers.Host)) { return; // no need } bool originAllowed = accessControlAllowOrigin.Contains("*") || accessControlAllowOrigin.Contains(originHeader); if (originAllowed) { controller.AddHeader("Access-Control-Allow-Origin", originHeader, msg); } if (controller.InnerRequest.Method.Method != "OPTIONS") { return; } controller.AddHeader("Access-Control-Allow-Credentials", "true", msg); controller.AddHeader("Access-Control-Max-Age", landlord.SystemConfiguration.AccessControlMaxAge, msg); controller.AddHeader("Access-Control-Allow-Methods", landlord.SystemConfiguration.AccessControlAllowMethods, msg); if (string.IsNullOrEmpty(landlord.SystemConfiguration.AccessControlRequestHeaders)) { // allow whatever headers are being requested var hdr = controller.GetHeader("Access-Control-Request-Headers"); // typically: "x-requested-with" if (hdr != null) { controller.AddHeader("Access-Control-Allow-Headers", hdr, msg); } } else { controller.AddHeader("Access-Control-Request-Headers", landlord.SystemConfiguration.AccessControlRequestHeaders, msg); } }
public IPrincipal GetUser(RavenBaseApiController controller) { if (controller.WasAlreadyAuthorizedUsingSingleAuthToken) { return(controller.User); } var hasApiKey = "True".Equals(controller.GetQueryStringValue("Has-Api-Key"), StringComparison.CurrentCultureIgnoreCase); var authHeader = controller.GetHeader("Authorization"); var hasOAuthTokenInCookie = controller.HasCookie("OAuth-Token"); if (hasApiKey || hasOAuthTokenInCookie || string.IsNullOrEmpty(authHeader) == false && authHeader.StartsWith("Bearer ")) { return(oAuthRequestAuthorizer.GetUser(controller, hasApiKey)); } return(windowsRequestAuthorizer.GetUser(controller)); }
public static bool IsGetRequest(RavenBaseApiController controller) { switch (controller.InnerRequest.Method.Method) { case "GET": case "HEAD": return(true); case "POST": var absolutePath = controller.InnerRequest.RequestUri.AbsolutePath; return(absolutePath.EndsWith("/queries", StringComparison.Ordinal) || absolutePath.EndsWith("/multi_get", StringComparison.Ordinal) || absolutePath.EndsWith("/multi_get/", StringComparison.Ordinal)); default: return(false); } }
private static HttpResponseMessage ProvideDebugAuthInfo(RavenBaseApiController controller, object msg) { string debugAuth = controller.GetQueryStringValue("debug-auth"); if (debugAuth == null) { return(controller.GetEmptyMessage()); } bool shouldProvideDebugAuthInformation; if (bool.TryParse(debugAuth, out shouldProvideDebugAuthInformation) && shouldProvideDebugAuthInformation) { return(controller.GetMessageWithObject(msg)); } return(controller.GetEmptyMessage()); }
private bool TryAuthorizeSingleUseAuthToken(RavenBaseApiController controller, string token, out HttpResponseMessage msg) { OneTimeToken value; if (singleUseAuthTokens.TryRemove(token, out value) == false) { msg = controller.GetMessageWithObject( new { Error = "Unknown single use token, maybe it was already used?" }, HttpStatusCode.Forbidden); return(false); } if (string.Equals(value.DatabaseName, controller.TenantName, StringComparison.InvariantCultureIgnoreCase) == false && (value.DatabaseName == "<system>" && controller.TenantName == null) == false) { msg = controller.GetMessageWithObject( new { Error = "This single use token cannot be used for this database" }, HttpStatusCode.Forbidden); return(false); } if ((SystemTime.UtcNow - value.GeneratedAt).TotalMinutes > 2.5) { msg = controller.GetMessageWithObject( new { Error = "This single use token has expired" }, HttpStatusCode.Forbidden); return(false); } if (value.User != null) { CurrentOperationContext.Headers.Value[Constants.RavenAuthenticatedUser] = value.User.Identity.Name; } CurrentOperationContext.User.Value = value.User; controller.User = value.User; msg = controller.GetEmptyMessage(); return(true); }
public AdminLogsConnectionState For(string id, RavenBaseApiController controller = null) { var connection = connections.GetOrAdd( id, _ => { IEventsTransport logsTransport = null; if (controller != null) { logsTransport = new LogsPushContent(controller); } var connectionState = new AdminLogsConnectionState(logsTransport); TimeSensitiveStore.Missing(id); return(connectionState); }); AlterEnabled(); return(connection); }
private bool TryAuthorizeSingleUseAuthToken(RavenBaseApiController controller, string token, out HttpResponseMessage msg) { if (controller.WasAlreadyAuthorizedUsingSingleAuthToken) { msg = controller.GetEmptyMessage(); return(true); } object result; HttpStatusCode statusCode; IPrincipal user; var resourceName = controller.ResourceName == null ? null : controller.ResourcePrefix + controller.ResourceName; var success = TryAuthorizeSingleUseAuthToken(token, resourceName, out result, out statusCode, out user); controller.User = user; msg = success == false?controller.GetMessageWithObject(result, statusCode) : controller.GetEmptyMessage(); controller.WasAlreadyAuthorizedUsingSingleAuthToken = success; return(success); }
private void TraceTraffic(RavenBaseApiController controller, LogHttpRequestStatsParams logHttpRequestStatsParams, string resourceName) { if (HasAnyHttpTraceEventTransport() == false) { return; } NotifyTrafficWatch(string.IsNullOrEmpty(resourceName) == false ? resourceName : Constants.SystemDatabase, new TrafficWatchNotification() { RequestUri = logHttpRequestStatsParams.RequestUri, ElapsedMilliseconds = logHttpRequestStatsParams.Stopwatch.ElapsedMilliseconds, CustomInfo = logHttpRequestStatsParams.CustomInfo, HttpMethod = logHttpRequestStatsParams.HttpMethod, ResponseStatusCode = logHttpRequestStatsParams.ResponseStatusCode, TenantName = NormalizeTennantName(resourceName), TimeStamp = SystemTime.UtcNow, InnerRequestsCount = logHttpRequestStatsParams.InnerRequestsCount } ); }
private void TraceTraffic(RavenBaseApiController controller, LogHttpRequestStatsParams logHttpRequestStatsParams, string databaseName) { if (HasAnyHttpTraceEventTransport() == false) { return; } NotifyTrafficWatch( new TrafficWatchNotification() { RequestUri = logHttpRequestStatsParams.RequestUri, ElapsedMilliseconds = logHttpRequestStatsParams.Stopwatch.ElapsedMilliseconds, CustomInfo = logHttpRequestStatsParams.CustomInfo, HttpMethod = logHttpRequestStatsParams.HttpMethod, ResponseStatusCode = logHttpRequestStatsParams.ResponseStatusCode, TenantName = NormalizeTennantName(databaseName), TimeStamp = SystemTime.UtcNow } ); }
public IPrincipal GetUser(RavenBaseApiController controller, bool hasApiKey) { var token = GetToken(controller); if (token == null) { WriteAuthorizationChallenge(controller, hasApiKey ? 412 : 401, "invalid_request", "The access token is required"); return(null); } AccessTokenBody tokenBody; if (!AccessToken.TryParseBody(controller.DatabasesLandlord.SystemConfiguration.OAuthTokenKey, token, out tokenBody)) { WriteAuthorizationChallenge(controller, 401, "invalid_token", "The access token is invalid"); return(null); } return(new OAuthPrincipal(tokenBody, null)); }
static string GetToken(RavenBaseApiController controller) { const string bearerPrefix = "Bearer "; var auth = controller.GetHeader("Authorization"); if (auth == null) { auth = controller.GetCookie("OAuth-Token"); if (auth != null) { auth = Uri.UnescapeDataString(auth); } } if (auth == null || auth.Length <= bearerPrefix.Length || !auth.StartsWith(bearerPrefix, StringComparison.OrdinalIgnoreCase)) { return(null); } var token = auth.Substring(bearerPrefix.Length, auth.Length - bearerPrefix.Length); return(token); }
private bool TryAuthorizeSingleUseAuthToken(RavenBaseApiController controller, string token, out HttpResponseMessage msg) { OneTimeToken value; if (singleUseAuthTokens.TryRemove(token, out value) == false) { msg = controller.GetMessageWithObject( new { Error = "Unknown single use token, maybe it was already used?" }, HttpStatusCode.Forbidden); return false; } if (string.Equals(value.DatabaseName, controller.TenantName, StringComparison.InvariantCultureIgnoreCase) == false && (value.DatabaseName == "<system>" && controller.TenantName == null) == false) { msg = controller.GetMessageWithObject( new { Error = "This single use token cannot be used for this database" }, HttpStatusCode.Forbidden); return false; } if ((SystemTime.UtcNow - value.GeneratedAt).TotalMinutes > 2.5) { msg = controller.GetMessageWithObject( new { Error = "This single use token has expired" }, HttpStatusCode.Forbidden); return false; } if (value.User != null) { CurrentOperationContext.Headers.Value[Constants.RavenAuthenticatedUser] = value.User.Identity.Name; } CurrentOperationContext.User.Value = value.User; controller.User = value.User; msg = controller.GetEmptyMessage(); return true; }
public async Task<HttpResponseMessage> HandleActualRequest(RavenBaseApiController controller, Func<Task<HttpResponseMessage>> action, Func<HttpException, HttpResponseMessage> onHttpException) { HttpResponseMessage response = null; cancellationToken.ThrowIfCancellationRequested(); Stopwatch sw = Stopwatch.StartNew(); try { Interlocked.Increment(ref concurrentRequests); if (IsWriteRequest(controller.InnerRequest)) { lastWriteRequest = SystemTime.UtcNow; } if (controller.SetupRequestToProperDatabase(this)) { response = await action(); } } catch (HttpException httpException) { response = onHttpException(httpException); } finally { Interlocked.Decrement(ref concurrentRequests); try { FinalizeRequestProcessing(controller, response, sw); } catch (Exception e) { var aggregateException = e as AggregateException; if (aggregateException != null) { e = aggregateException.ExtractSingleInnerException(); } Logger.ErrorException("Could not finalize request properly", e); } } return response; }
private void FinalizeRequestProcessing(RavenBaseApiController controller, HttpResponseMessage response, Stopwatch sw) { LogHttpRequestStatsParams logHttpRequestStatsParam = null; try { StringBuilder sb = null; if (controller.CustomRequestTraceInfo != null && controller.CustomRequestTraceInfo.Count > 0) { sb = new StringBuilder(); foreach (var action in controller.CustomRequestTraceInfo) { try { action(sb); } catch (Exception e) { Logger.WarnException("Could not gather information to log request stats custom info, so far got " + sb, e); } sb.AppendLine(); } while (sb.Length > 0) { if (!char.IsWhiteSpace(sb[sb.Length - 1])) { break; } sb.Length--; } } var innerRequest = controller.InnerRequest; var httpRequestHeaders = innerRequest.Headers; var httpContentHeaders = innerRequest.Content == null ? null : innerRequest.Content.Headers; logHttpRequestStatsParam = new LogHttpRequestStatsParams( sw, new Lazy <HttpHeaders>(() => RavenBaseApiController.CloneRequestHttpHeaders(httpRequestHeaders, httpContentHeaders)), controller.InnerRequest.Method.Method, response != null ? (int)response.StatusCode : 500, controller.InnerRequest.RequestUri.ToString(), sb != null ? sb.ToString() : null, controller.InnerRequestsCount ); } catch (Exception e) { Logger.WarnException("Could not gather information to log request stats", e); } if (logHttpRequestStatsParam == null || sw == null) { return; } sw.Stop(); if (landlord.IsDatabaseLoaded(controller.TenantName ?? Constants.SystemDatabase)) { controller.MarkRequestDuration(sw.ElapsedMilliseconds); } var curReq = Interlocked.Increment(ref reqNum); LogHttpRequestStats(controller, logHttpRequestStatsParam, controller.TenantName, curReq); if (controller.IsInternalRequest == false) { TraceTraffic(controller, logHttpRequestStatsParam, controller.TenantName); } RememberRecentRequests(logHttpRequestStatsParam, controller.TenantName); }
public bool TryAuthorize(RavenBaseApiController controller, bool ignoreDb, out HttpResponseMessage msg) { Func <HttpResponseMessage> onRejectingRequest; var tenantId = controller.TenantName ?? Constants.SystemDatabase; var userCreated = TryCreateUser(controller, tenantId, out onRejectingRequest); if (server.SystemConfiguration.AnonymousUserAccessMode == AnonymousUserAccessMode.None && userCreated == false) { msg = onRejectingRequest(); return(false); } PrincipalWithDatabaseAccess user = null; if (userCreated) { user = (PrincipalWithDatabaseAccess)controller.User; CurrentOperationContext.Headers.Value[Constants.RavenAuthenticatedUser] = controller.User.Identity.Name; CurrentOperationContext.User.Value = controller.User; // admins always go through if (user.Principal.IsAdministrator(server.SystemConfiguration.AnonymousUserAccessMode)) { msg = controller.GetEmptyMessage(); return(true); } // backup operators can go through if (user.Principal.IsBackupOperator(server.SystemConfiguration.AnonymousUserAccessMode)) { msg = controller.GetEmptyMessage(); return(true); } } bool isGetRequest = IsGetRequest(controller.InnerRequest.Method.Method, controller.InnerRequest.RequestUri.AbsolutePath); switch (server.SystemConfiguration.AnonymousUserAccessMode) { case AnonymousUserAccessMode.Admin: case AnonymousUserAccessMode.All: msg = controller.GetEmptyMessage(); return(true); // if we have, doesn't matter if we have / don't have the user case AnonymousUserAccessMode.Get: if (isGetRequest) { msg = controller.GetEmptyMessage(); return(true); } goto case AnonymousUserAccessMode.None; case AnonymousUserAccessMode.None: if (userCreated) { if (string.IsNullOrEmpty(tenantId) || tenantId.StartsWith("fs/") == false) { if (user.AdminDatabases.Contains(tenantId) || user.AdminDatabases.Contains("*") || ignoreDb) { msg = controller.GetEmptyMessage(); return(true); } if (user.ReadWriteDatabases.Contains(tenantId) || user.ReadWriteDatabases.Contains("*")) { msg = controller.GetEmptyMessage(); return(true); } if (isGetRequest && (user.ReadOnlyDatabases.Contains(tenantId) || user.ReadOnlyDatabases.Contains("*"))) { msg = controller.GetEmptyMessage(); return(true); } } else if (tenantId.StartsWith("fs/")) { tenantId = tenantId.Substring(3, tenantId.Length - "fs/".Length); if (user.ReadWriteFileSystems.Contains(tenantId) || user.ReadWriteFileSystems.Contains("*")) { msg = controller.GetEmptyMessage(); return(true); } if (isGetRequest && (user.ReadOnlyFileSystems.Contains(tenantId) || user.ReadOnlyFileSystems.Contains("*"))) { msg = controller.GetEmptyMessage(); return(true); } } else { throw new ArgumentOutOfRangeException("tenantId", "We don't know how to authorize unknown tenant id: " + tenantId); } } msg = onRejectingRequest(); return(false); default: throw new ArgumentOutOfRangeException(); } }
private PrincipalWithDatabaseAccess UpdateUserPrincipal(RavenBaseApiController controller, List<ResourceAccess> databaseAccessLists) { var access = controller.User as PrincipalWithDatabaseAccess; if (access != null) return access; var user = new PrincipalWithDatabaseAccess((WindowsPrincipal)controller.User); foreach (var databaseAccess in databaseAccessLists) { if (databaseAccess.Admin) user.AdminDatabases.Add(databaseAccess.TenantId); else if (databaseAccess.ReadOnly) user.ReadOnlyDatabases.Add(databaseAccess.TenantId); else user.ReadWriteDatabases.Add(databaseAccess.TenantId); } controller.User = user; Thread.CurrentPrincipal = user; return user; }
public bool TryAuthorize(RavenBaseApiController controller, bool ignoreDb, out HttpResponseMessage msg) { Func<HttpResponseMessage> onRejectingRequest; var tenantId = controller.TenantName ?? Constants.SystemDatabase; var userCreated = TryCreateUser(controller, tenantId, out onRejectingRequest); if (server.SystemConfiguration.AnonymousUserAccessMode == AnonymousUserAccessMode.None && userCreated == false) { msg = onRejectingRequest(); return false; } PrincipalWithDatabaseAccess user = null; if (userCreated) { user = (PrincipalWithDatabaseAccess)controller.User; CurrentOperationContext.Headers.Value[Constants.RavenAuthenticatedUser] = controller.User.Identity.Name; CurrentOperationContext.User.Value = controller.User; // admins always go through if (user.Principal.IsAdministrator(server.SystemConfiguration.AnonymousUserAccessMode)) { msg = controller.GetEmptyMessage(); return true; } // backup operators can go through if (user.Principal.IsBackupOperator(server.SystemConfiguration.AnonymousUserAccessMode)) { msg = controller.GetEmptyMessage(); return true; } } bool isGetRequest = IsGetRequest(controller.InnerRequest.Method.Method, controller.InnerRequest.RequestUri.AbsolutePath); switch (server.SystemConfiguration.AnonymousUserAccessMode) { case AnonymousUserAccessMode.Admin: case AnonymousUserAccessMode.All: msg = controller.GetEmptyMessage(); return true; // if we have, doesn't matter if we have / don't have the user case AnonymousUserAccessMode.Get: if (isGetRequest) { msg = controller.GetEmptyMessage(); return true; } goto case AnonymousUserAccessMode.None; case AnonymousUserAccessMode.None: if (userCreated) { if (string.IsNullOrEmpty(tenantId) == false && tenantId.StartsWith("fs/")) tenantId = tenantId.Substring(3); if (string.IsNullOrEmpty(tenantId) == false && tenantId.StartsWith("counters/")) tenantId = tenantId.Substring(9); if (user.AdminDatabases.Contains(tenantId) || user.AdminDatabases.Contains("*") || ignoreDb) { msg = controller.GetEmptyMessage(); return true; } if (user.ReadWriteDatabases.Contains(tenantId) || user.ReadWriteDatabases.Contains("*")) { msg = controller.GetEmptyMessage(); return true; } if (isGetRequest && (user.ReadOnlyDatabases.Contains(tenantId) || user.ReadOnlyDatabases.Contains("*"))) { msg = controller.GetEmptyMessage(); return true; } } msg = onRejectingRequest(); return false; default: throw new ArgumentOutOfRangeException(); } }
private void TraceTraffic(RavenBaseApiController controller, LogHttpRequestStatsParams logHttpRequestStatsParams, string databaseName) { if (HasAnyHttpTraceEventTransport() == false) return; NotifyTrafficWatch( new TrafficWatchNotification() { RequestUri = logHttpRequestStatsParams.RequestUri, ElapsedMilliseconds = logHttpRequestStatsParams.Stopwatch.ElapsedMilliseconds, CustomInfo = logHttpRequestStatsParams.CustomInfo, HttpMethod = logHttpRequestStatsParams.HttpMethod, ResponseStatusCode = logHttpRequestStatsParams.ResponseStatusCode, TenantName = NormalizeTennantName(databaseName), TimeStamp = SystemTime.UtcNow, InnerRequestsCount = logHttpRequestStatsParams.InnerRequestsCount } ); }
private void LogHttpRequestStats(RavenBaseApiController controller, LogHttpRequestStatsParams logHttpRequestStatsParams, string databaseName, long curReq) { if (Logger.IsDebugEnabled == false) return; if (controller is StudioController || controller is HardRouteController || controller is SilverlightController) return; var message = string.Format(CultureInfo.InvariantCulture, "Request #{0,4:#,0}: {1,-7} - {2,5:#,0} ms - {5,-10} - {3} - {4}", curReq, logHttpRequestStatsParams.HttpMethod, logHttpRequestStatsParams.Stopwatch.ElapsedMilliseconds, logHttpRequestStatsParams.ResponseStatusCode, logHttpRequestStatsParams.RequestUri, databaseName); Logger.Debug(message); if (string.IsNullOrWhiteSpace(logHttpRequestStatsParams.CustomInfo) == false) { Logger.Debug(logHttpRequestStatsParams.CustomInfo); } }
HttpResponseMessage WriteAuthorizationChallenge(RavenBaseApiController controller, int statusCode, string error, string errorDescription) { var msg = controller.GetEmptyMessage(); var systemConfiguration = controller.SystemConfiguration; if (string.IsNullOrEmpty(systemConfiguration.OAuthTokenServer) == false) { if (systemConfiguration.UseDefaultOAuthTokenServer == false) { controller.AddHeader("OAuth-Source", systemConfiguration.OAuthTokenServer, msg); } else { controller.AddHeader("OAuth-Source", new UriBuilder(systemConfiguration.OAuthTokenServer) { Host = controller.InnerRequest.RequestUri.Host, Port = controller.InnerRequest.RequestUri.Port }.Uri.ToString(), msg); } } msg.StatusCode = (HttpStatusCode)statusCode; msg.Headers.Add("WWW-Authenticate", string.Format("Bearer realm=\"Raven\", error=\"{0}\",error_description=\"{1}\"", error, errorDescription)); return msg; }
// Cross-Origin Resource Sharing (CORS) is documented here: http://www.w3.org/TR/cors/ public void AddAccessControlHeaders(RavenBaseApiController controller, HttpResponseMessage msg) { var accessControlAllowOrigin = landlord.SystemConfiguration.AccessControlAllowOrigin; if (accessControlAllowOrigin.Count == 0) return; var originHeader = controller.GetHeader("Origin"); if (originHeader == null || originHeader.Contains(controller.InnerRequest.Headers.Host)) return; // no need bool originAllowed = accessControlAllowOrigin.Contains("*") || accessControlAllowOrigin.Contains(originHeader); if (originAllowed) { controller.AddHeader("Access-Control-Allow-Origin", originHeader, msg); } if (controller.InnerRequest.Method.Method != "OPTIONS") return; controller.AddHeader("Access-Control-Allow-Credentials", "true", msg); controller.AddHeader("Access-Control-Max-Age", landlord.SystemConfiguration.AccessControlMaxAge, msg); controller.AddHeader("Access-Control-Allow-Methods", landlord.SystemConfiguration.AccessControlAllowMethods, msg); if (string.IsNullOrEmpty(landlord.SystemConfiguration.AccessControlRequestHeaders)) { // allow whatever headers are being requested var hdr = controller.GetHeader("Access-Control-Request-Headers"); // typically: "x-requested-with" if (hdr != null) controller.AddHeader("Access-Control-Allow-Headers", hdr, msg); } else { controller.AddHeader("Access-Control-Request-Headers", landlord.SystemConfiguration.AccessControlRequestHeaders, msg); } }
static string GetToken(RavenBaseApiController controller) { const string bearerPrefix = "Bearer "; var auth = controller.GetHeader("Authorization"); if (auth == null) { auth = controller.GetCookie("OAuth-Token"); if (auth != null) auth = Uri.UnescapeDataString(auth); } if (auth == null || auth.Length <= bearerPrefix.Length || !auth.StartsWith(bearerPrefix, StringComparison.OrdinalIgnoreCase)) return null; var token = auth.Substring(bearerPrefix.Length, auth.Length - bearerPrefix.Length); return token; }
// Cross-Origin Resource Sharing (CORS) is documented here: http://www.w3.org/TR/cors/ public void AddAccessControlHeaders(RavenBaseApiController controller, HttpResponseMessage msg) { if (string.IsNullOrEmpty(landlord.SystemConfiguration.AccessControlAllowOrigin)) return; controller.AddHeader("Access-Control-Allow-Credentials", "true", msg); bool originAllowed = landlord.SystemConfiguration.AccessControlAllowOrigin == "*" || landlord.SystemConfiguration.AccessControlAllowOrigin.Split(' ') .Any(o => o == controller.GetHeader("Origin")); if (originAllowed) { controller.AddHeader("Access-Control-Allow-Origin", controller.GetHeader("Origin"), msg); } controller.AddHeader("Access-Control-Max-Age", landlord.SystemConfiguration.AccessControlMaxAge, msg); controller.AddHeader("Access-Control-Allow-Methods", landlord.SystemConfiguration.AccessControlAllowMethods, msg); if (string.IsNullOrEmpty(landlord.SystemConfiguration.AccessControlRequestHeaders)) { // allow whatever headers are being requested var hdr = controller.GetHeader("Access-Control-Request-Headers"); // typically: "x-requested-with" if (hdr != null) controller.AddHeader("Access-Control-Allow-Headers", hdr, msg); } else { controller.AddHeader("Access-Control-Request-Headers", landlord.SystemConfiguration.AccessControlRequestHeaders, msg); } }
private void FinalizeRequestProcessing(IResourceApiController controller, HttpResponseMessage response, Stopwatch sw) { LogHttpRequestStatsParams logHttpRequestStatsParam = null; try { StringBuilder sb = null; if (controller.CustomRequestTraceInfo != null && controller.CustomRequestTraceInfo.Count > 0) { sb = new StringBuilder(); foreach (var action in controller.CustomRequestTraceInfo) { try { action(sb); } catch (Exception e) { Logger.WarnException("Could not gather information to log request stats custom info, so far got " + sb, e); } sb.AppendLine(); } while (sb.Length > 0) { if (!char.IsWhiteSpace(sb[sb.Length - 1])) { break; } sb.Length--; } } var innerRequest = controller.InnerRequest; var httpRequestHeaders = innerRequest.Headers; var httpContentHeaders = innerRequest.Content == null ? null : innerRequest.Content.Headers; logHttpRequestStatsParam = new LogHttpRequestStatsParams( sw, new Lazy <HttpHeaders>(() => RavenBaseApiController.CloneRequestHttpHeaders(httpRequestHeaders, httpContentHeaders)), controller.InnerRequest.Method.Method, response != null ? (int)response.StatusCode : 500, controller.InnerRequest.RequestUri.ToString(), sb != null ? sb.ToString() : null, controller.InnerRequestsCount ); } catch (Exception e) { Logger.WarnException("Could not gather information to log request stats", e); } if (logHttpRequestStatsParam == null || sw == null) { return; } sw.Stop(); MarkRequestDuration(controller, sw.ElapsedMilliseconds); object requestNumber; if (controller.InnerRequest.Properties.TryGetValue("requestNum", out requestNumber) && requestNumber is long) { LogHttpRequestStats(controller, logHttpRequestStatsParam, controller.ResourceName, (long)requestNumber); } if (controller.IsInternalRequest == false) { TraceTraffic(controller, logHttpRequestStatsParam, controller.ResourceName, response); } RememberRecentRequests(logHttpRequestStatsParam, controller.ResourceName); }
private bool TryAuthorizeSingleUseAuthToken(RavenBaseApiController controller, string token, out HttpResponseMessage msg) { if (controller.WasAlreadyAuthorizedUsingSingleAuthToken) { msg = controller.GetEmptyMessage(); return true; } object result; HttpStatusCode statusCode; IPrincipal user; var success = TryAuthorizeSingleUseAuthToken(token, controller.TenantName, out result, out statusCode, out user); controller.User = user; if (success == false) msg = controller.GetMessageWithObject(result, statusCode); else msg = controller.GetEmptyMessage(); controller.WasAlreadyAuthorizedUsingSingleAuthToken = success; return success; }
public HttpTracePushContent(RavenBaseApiController controller) { Connected = true; }
private void FinalizeRequestProcessing(RavenBaseApiController controller, HttpResponseMessage response, Stopwatch sw) { LogHttpRequestStatsParams logHttpRequestStatsParam = null; try { StringBuilder sb = null; if (controller.CustomRequestTraceInfo != null) { sb = new StringBuilder(); foreach (var action in controller.CustomRequestTraceInfo) { action(sb); sb.AppendLine(); } while (sb.Length > 0) { if (!char.IsWhiteSpace(sb[sb.Length - 1])) break; sb.Length--; } } logHttpRequestStatsParam = new LogHttpRequestStatsParams( sw, GetHeaders(controller.InnerHeaders), controller.InnerRequest.Method.Method, response != null ? (int) response.StatusCode : 500, controller.InnerRequest.RequestUri.PathAndQuery, sb != null ? sb.ToString() : null ); } catch (Exception e) { Logger.WarnException("Could not gather information to log request stats", e); } if (logHttpRequestStatsParam == null || sw == null) return; sw.Stop(); controller.MarkRequestDuration(sw.ElapsedMilliseconds); LogHttpRequestStats(logHttpRequestStatsParam, controller.TenantName); TraceRequest(logHttpRequestStatsParam, controller.TenantName); }
public bool TryAuthorize(RavenBaseApiController controller, bool hasApiKey, bool ignoreDbAccess, out HttpResponseMessage msg) { var isGetRequest = IsGetRequest(controller); var allowUnauthenticatedUsers = // we need to auth even if we don't have to, for bundles that want the user Settings.AnonymousUserAccessMode == AnonymousUserAccessMode.All || Settings.AnonymousUserAccessMode == AnonymousUserAccessMode.Admin || Settings.AnonymousUserAccessMode == AnonymousUserAccessMode.Get && isGetRequest; var token = GetToken(controller); if (token == null) { if (allowUnauthenticatedUsers) { msg = controller.GetEmptyMessage(); return(true); } msg = WriteAuthorizationChallenge(controller, hasApiKey ? 412 : 401, "invalid_request", "The access token is required"); return(false); } AccessTokenBody tokenBody; if (!AccessToken.TryParseBody(Settings.OAuthTokenKey, token, out tokenBody)) { if (allowUnauthenticatedUsers) { msg = controller.GetEmptyMessage(); return(true); } msg = WriteAuthorizationChallenge(controller, 401, "invalid_token", "The access token is invalid"); return(false); } if (tokenBody.IsExpired()) { if (allowUnauthenticatedUsers) { msg = controller.GetEmptyMessage(); return(true); } msg = WriteAuthorizationChallenge(controller, 401, "invalid_token", "The access token is expired"); return(false); } var writeAccess = isGetRequest == false; if (!tokenBody.IsAuthorized(controller.ResourceName, writeAccess)) { if (allowUnauthenticatedUsers || ignoreDbAccess) { msg = controller.GetEmptyMessage(); return(true); } msg = WriteAuthorizationChallenge(controller, 403, "insufficient_scope", writeAccess ? "Not authorized for read/write access for tenant " + controller.ResourceName : "Not authorized for tenant " + controller.ResourceName); return(false); } controller.User = new OAuthPrincipal(tokenBody, controller.ResourceName); CurrentOperationContext.User.Value = controller.User; msg = controller.GetEmptyMessage(); return(true); }
public bool TryAuthorize(RavenBaseApiController controller, bool hasApiKey, bool ignoreDbAccess, out HttpResponseMessage msg) { var isGetRequest = IsGetRequest(controller.InnerRequest.Method.Method, controller.InnerRequest.RequestUri.AbsolutePath); var allowUnauthenticatedUsers = // we need to auth even if we don't have to, for bundles that want the user Settings.AnonymousUserAccessMode == AnonymousUserAccessMode.All || Settings.AnonymousUserAccessMode == AnonymousUserAccessMode.Admin || Settings.AnonymousUserAccessMode == AnonymousUserAccessMode.Get && isGetRequest; var token = GetToken(controller); if (token == null) { if (allowUnauthenticatedUsers) { msg = controller.GetEmptyMessage(); return true; } msg = WriteAuthorizationChallenge(controller, hasApiKey ? 412 : 401, "invalid_request", "The access token is required"); return false; } AccessTokenBody tokenBody; if (!AccessToken.TryParseBody(Settings.OAuthTokenKey, token, out tokenBody)) { if (allowUnauthenticatedUsers) { msg = controller.GetEmptyMessage(); return true; } msg = WriteAuthorizationChallenge(controller, 401, "invalid_token", "The access token is invalid"); return false; } if (tokenBody.IsExpired()) { if (allowUnauthenticatedUsers) { msg = controller.GetEmptyMessage(); return true; } msg = WriteAuthorizationChallenge(controller, 401, "invalid_token", "The access token is expired"); return false; } var writeAccess = isGetRequest == false; if (!tokenBody.IsAuthorized(controller.TenantName, writeAccess)) { if (allowUnauthenticatedUsers || ignoreDbAccess) { msg = controller.GetEmptyMessage(); return true; } msg = WriteAuthorizationChallenge(controller, 403, "insufficient_scope", writeAccess ? "Not authorized for read/write access for tenant " + controller.TenantName : "Not authorized for tenant " + controller.TenantName); return false; } controller.User = new OAuthPrincipal(tokenBody, controller.TenantName); CurrentOperationContext.Headers.Value[Constants.RavenAuthenticatedUser] = tokenBody.UserId; CurrentOperationContext.User.Value = controller.User; msg = controller.GetEmptyMessage(); return true; }
public AdminLogsConnectionState For(string id, RavenBaseApiController controller = null) { var connection = connections.GetOrAdd( id, _ => { IEventsTransport logsTransport = null; if (controller != null) logsTransport = new LogsPushContent(controller); var connectionState = new AdminLogsConnectionState(logsTransport); TimeSensitiveStore.Missing(id); return connectionState; }); AlterEnabled(); return connection; }
public async Task<HttpResponseMessage> HandleActualRequest(RavenBaseApiController controller, HttpControllerContext controllerContext, Func<Task<HttpResponseMessage>> action, Func<HttpException, HttpResponseMessage> onHttpException) { HttpResponseMessage response = null; cancellationToken.ThrowIfCancellationRequested(); Stopwatch sw = Stopwatch.StartNew(); try { Interlocked.Increment(ref concurrentRequests); if (controller.SetupRequestToProperDatabase(this)) { if (controller.ResourceConfiguration.RejectClientsMode && controllerContext.Request.Headers.Contains(Constants.RavenClientVersion)) { response = new HttpResponseMessage(HttpStatusCode.ServiceUnavailable) { Content = new StringContent("This service is not accepting clients calls") }; } else { response = await action(); } } } catch (HttpException httpException) { response = onHttpException(httpException); } finally { Interlocked.Decrement(ref concurrentRequests); try { FinalizeRequestProcessing(controller, response, sw); } catch (Exception e) { var aggregateException = e as AggregateException; if (aggregateException != null) { e = aggregateException.ExtractSingleInnerException(); } Logger.ErrorException("Could not finalize request properly", e); } } return response; }
private bool TryCreateUser(RavenBaseApiController controller, string databaseName, out Func<HttpResponseMessage> onRejectingRequest) { var invalidUser = (controller.User == null || controller.User.Identity.IsAuthenticated == false); if (invalidUser) { onRejectingRequest = () => { var msg = ProvideDebugAuthInfo(controller, new { Reason = "User is null or not authenticated" }); controller.AddHeader("Raven-Required-Auth", "Windows", msg); if (string.IsNullOrEmpty(controller.SystemConfiguration.OAuthTokenServer) == false) { controller.AddHeader("OAuth-Source", controller.SystemConfiguration.OAuthTokenServer, msg); } msg.StatusCode = HttpStatusCode.Unauthorized; return msg; }; return false; } var dbUsersIsAllowedAccessTo = requiredUsers .Where(data => controller.User.Identity.Name.Equals(data.Name, StringComparison.InvariantCultureIgnoreCase)) .SelectMany(source => source.Databases) .Concat(requiredGroups.Where(data => controller.User.IsInRole(data.Name)).SelectMany(x => x.Databases)) .ToList(); var user = UpdateUserPrincipal(controller, dbUsersIsAllowedAccessTo); onRejectingRequest = () => { var msg = ProvideDebugAuthInfo(controller, new { user.Identity.Name, user.AdminDatabases, user.ReadOnlyDatabases, user.ReadWriteDatabases, DatabaseName = databaseName }); msg.StatusCode = HttpStatusCode.Forbidden; throw new HttpResponseException(msg); }; return true; }
private void FinalizeRequestProcessing(RavenBaseApiController controller, HttpResponseMessage response, Stopwatch sw) { LogHttpRequestStatsParams logHttpRequestStatsParam = null; try { StringBuilder sb = null; if (controller.CustomRequestTraceInfo != null && controller.CustomRequestTraceInfo.Count > 0) { sb = new StringBuilder(); foreach (var action in controller.CustomRequestTraceInfo) { action(sb); sb.AppendLine(); } while (sb.Length > 0) { if (!char.IsWhiteSpace(sb[sb.Length - 1])) break; sb.Length--; } } logHttpRequestStatsParam = new LogHttpRequestStatsParams( sw, GetHeaders(controller.InnerHeaders), controller.InnerRequest.Method.Method, response != null ? (int)response.StatusCode : 500, controller.InnerRequest.RequestUri.ToString(), sb != null ? sb.ToString() : null, controller.InnerRequestsCount ); } catch (Exception e) { Logger.WarnException("Could not gather information to log request stats", e); } if (logHttpRequestStatsParam == null || sw == null) return; sw.Stop(); if (landlord.IsDatabaseLoaded(controller.TenantName ?? Constants.SystemDatabase)) { controller.MarkRequestDuration(sw.ElapsedMilliseconds); } var curReq = Interlocked.Increment(ref reqNum); LogHttpRequestStats(controller, logHttpRequestStatsParam, controller.TenantName, curReq); if (controller.IsInternalRequest == false) { TraceTraffic(controller, logHttpRequestStatsParam, controller.TenantName); } RememberRecentRequests(logHttpRequestStatsParam, controller.TenantName); }
private static HttpResponseMessage ProvideDebugAuthInfo(RavenBaseApiController controller, object msg) { string debugAuth = controller.GetQueryStringValue("debug-auth"); if (debugAuth == null) return controller.GetEmptyMessage(); bool shouldProvideDebugAuthInformation; if (bool.TryParse(debugAuth, out shouldProvideDebugAuthInformation) && shouldProvideDebugAuthInformation) { return controller.GetMessageWithObject(msg); } return controller.GetEmptyMessage(); }
private void LogHttpRequestStats(RavenBaseApiController controller, LogHttpRequestStatsParams logHttpRequestStatsParams, string databaseName, long curReq) { if (Logger.IsDebugEnabled == false) return; if (controller is StudioController || controller is HardRouteController || controller is SilverlightController) return; // we filter out requests for the UI because they fill the log with information // we probably don't care about them anyway. That said, we do output them if they take too // long. if (logHttpRequestStatsParams.Headers["Raven-Timer-Request"] == "true" && logHttpRequestStatsParams.Stopwatch.ElapsedMilliseconds <= 25) return; var message = string.Format(CultureInfo.InvariantCulture, "Request #{0,4:#,0}: {1,-7} - {2,5:#,0} ms - {5,-10} - {3} - {4}", curReq, logHttpRequestStatsParams.HttpMethod, logHttpRequestStatsParams.Stopwatch.ElapsedMilliseconds, logHttpRequestStatsParams.ResponseStatusCode, logHttpRequestStatsParams.RequestUri, databaseName); Logger.Debug(message); if (string.IsNullOrWhiteSpace(logHttpRequestStatsParams.CustomInfo) == false) { Logger.Debug(logHttpRequestStatsParams.CustomInfo); } }
public ConnectionState For(string id, RavenBaseApiController controller = null) { return connections.GetOrAdd(id, _ => { IEventsTransport eventsTransport = null; if (controller != null) eventsTransport = new ChangesPushContent(controller); var connectionState = new ConnectionState(eventsTransport); TimeSensitiveStore.Missing(id); return connectionState; }); }