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);
		}
Beispiel #2
0
        public LogsPushContent(RavenBaseApiController controller)
		{
			Connected = true;
			Id = controller.GetQueryStringValue("id");
            
			if (string.IsNullOrEmpty(Id))
				throw new ArgumentException("Id is mandatory");
		}
Beispiel #3
0
        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;
		}
		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 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 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
			}
			);
		}
		// 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);
			}
		}
        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;
		}
        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;
		}
Beispiel #11
0
		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);
			}
		}
Beispiel #12
0
 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;
     });
 }
Beispiel #13
0
        public HttpTracePushContent(RavenBaseApiController controller)
		{
			Connected = true;
		}
Beispiel #14
0
        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;
        }
Beispiel #15
0
	    // 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);
			}
		}
Beispiel #16
0
        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);

		}
        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 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;
		}
        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;
		}
		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 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 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 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;
        }
		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);
			}
		}
        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;
		}