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 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, 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); }
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); }
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); }
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); }
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; }
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 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 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(); }
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); }
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 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(); } }
public bool TryAuthorize(RavenBaseApiController controller, bool ignoreDb, out HttpResponseMessage msg) { Func <HttpResponseMessage> onRejectingRequest; var tenantId = controller.ResourceName ?? Constants.SystemDatabase; var userCreated = TryCreateUser(controller, tenantId, out onRejectingRequest); if (server.SystemConfiguration.Core.AnonymousUserAccessMode == AnonymousUserAccessMode.None && userCreated == false) { msg = onRejectingRequest(); return(false); } PrincipalWithDatabaseAccess user = null; if (userCreated) { user = (PrincipalWithDatabaseAccess)controller.User; CurrentOperationContext.User.Value = controller.User; // admins always go through if (user.Principal.IsAdministrator(server.SystemConfiguration.Core.AnonymousUserAccessMode)) { msg = controller.GetEmptyMessage(); return(true); } // backup operators can go through if (user.Principal.IsBackupOperator(server.SystemConfiguration.Core.AnonymousUserAccessMode)) { msg = controller.GetEmptyMessage(); return(true); } } bool isGetRequest = IsGetRequest(controller); switch (server.SystemConfiguration.Core.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/", StringComparison.OrdinalIgnoreCase) || tenantId.StartsWith("cs/", StringComparison.OrdinalIgnoreCase) || tenantId.StartsWith("ts/", StringComparison.OrdinalIgnoreCase))) { tenantId = tenantId.Substring(3); } 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 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; }