├── .gitignore ├── .nuget ├── NuGet.Config ├── NuGet.exe └── NuGet.targets ├── Devbridge.AzurePowerTools.sln ├── Devbridge.BackupDatabaseAzureStorage ├── App.config ├── Devbridge.BackupDatabaseAzureStorage.csproj ├── ExportFacade.cs ├── ImportExportHelper.cs ├── NLog.config ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Settings.Designer.cs │ └── Settings.settings ├── Service References │ └── DACWebService │ │ ├── Devbridge.BackupDatabaseAzureStorage.DACWebService.StatusInfo.datasource │ │ ├── Microsoft.SqlServer.Management.Dac.ServiceTypes.xsd │ │ ├── Microsoft.SqlServer.Management.Dac.Services.wsdl │ │ ├── Reference.cs │ │ ├── Reference.svcmap │ │ ├── configuration.svcinfo │ │ ├── configuration91.svcinfo │ │ ├── service.wsdl │ │ ├── service.xsd │ │ └── service1.xsd └── packages.config ├── Devbridge.BackupDatabaseServer ├── App.config ├── Devbridge.BackupDatabaseServer.csproj ├── ExportFacade.cs ├── NLog.config ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Settings.Designer.cs │ └── Settings.settings ├── Service References │ └── DACWebService │ │ ├── Devbridge.BackupDatabaseServer.DACWebService.StatusInfo.datasource │ │ ├── Microsoft.SqlServer.Management.Dac.ServiceTypes.xsd │ │ ├── Microsoft.SqlServer.Management.Dac.Services.wsdl │ │ ├── Reference.cs │ │ ├── Reference.svcmap │ │ ├── configuration.svcinfo │ │ ├── configuration91.svcinfo │ │ ├── service.wsdl │ │ ├── service.xsd │ │ └── service1.xsd ├── packages.config └── readme.txt ├── Devbridge.BasicAuthentication.Test ├── Config │ └── basicAuthentication.config ├── Controllers │ └── HomeController.cs ├── Devbridge.BasicAuthentication.Test.csproj ├── Global.asax ├── Global.asax.cs ├── Properties │ └── AssemblyInfo.cs ├── Views │ ├── Home │ │ └── Index.cshtml │ ├── Shared │ │ ├── Error.cshtml │ │ └── _Layout.cshtml │ ├── Web.config │ └── _ViewStart.cshtml ├── Web.Debug.config ├── Web.Release.config ├── Web.config └── packages.config ├── Devbridge.BasicAuthentication ├── BasicAuthenticationModule.cs ├── Config │ └── basicAuthentication.config ├── Configuration │ ├── BasicAuthenticationConfigurationSection.cs │ ├── CredentialElement.cs │ ├── CredentialElementCollection.cs │ ├── ExcludeElement.cs │ └── ExcludeElementCollection.cs ├── Devbridge.BasicAuthentication.csproj ├── Devbridge.BasicAuthentication.nuspec ├── Properties │ └── AssemblyInfo.cs ├── web.config.install.xdt └── web.config.uninstall.xdt ├── PowerShell └── PublishCloudService.ps1 ├── README.md ├── SharedAssemblyInfo.cs ├── license.txt └── packages └── repositories.config /.gitignore: -------------------------------------------------------------------------------- 1 | obj 2 | bin 3 | deploy 4 | deploy/* 5 | _ReSharper.* 6 | *.resharper 7 | *.suo 8 | *.cache 9 | ~$* 10 | *.user 11 | 12 | #Nuget 13 | packages/** 14 | !packages/repositories.config 15 | !packages.config 16 | -------------------------------------------------------------------------------- /.nuget/NuGet.Config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.nuget/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/devbridge/AzurePowerTools/eaf2e7d9189a09e2bb04c1da6407a9d70edd936e/.nuget/NuGet.exe -------------------------------------------------------------------------------- /.nuget/NuGet.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(MSBuildProjectDirectory)\..\ 5 | 6 | 7 | false 8 | 9 | 10 | false 11 | 12 | 13 | true 14 | 15 | 16 | false 17 | 18 | 19 | 20 | 21 | 22 | 26 | 27 | 28 | 29 | 30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) 31 | $([System.IO.Path]::Combine($(ProjectDir), "packages.config")) 32 | 33 | 34 | 35 | 36 | $(SolutionDir).nuget 37 | packages.config 38 | 39 | 40 | 41 | 42 | $(NuGetToolsPath)\nuget.exe 43 | @(PackageSource) 44 | 45 | "$(NuGetExePath)" 46 | mono --runtime=v4.0.30319 $(NuGetExePath) 47 | 48 | $(TargetDir.Trim('\\')) 49 | 50 | -RequireConsent 51 | 52 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(RequireConsentSwitch) -solutionDir "$(SolutionDir) " 53 | $(NuGetCommand) pack "$(ProjectPath)" -p Configuration=$(Configuration) -o "$(PackageOutputDir)" -symbols 54 | 55 | 56 | 57 | RestorePackages; 58 | $(BuildDependsOn); 59 | 60 | 61 | 62 | 63 | $(BuildDependsOn); 64 | BuildPackage; 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 87 | 88 | 91 | 92 | 93 | 94 | 96 | 97 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 148 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /Devbridge.AzurePowerTools.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{743822B6-591F-46ED-88C6-BC4B236DEFE5}" 7 | ProjectSection(SolutionItems) = preProject 8 | SharedAssemblyInfo.cs = SharedAssemblyInfo.cs 9 | EndProjectSection 10 | EndProject 11 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PowerShell", "PowerShell", "{B7FDCCA1-5E95-4F04-8515-FD9BB2DEDA98}" 12 | ProjectSection(SolutionItems) = preProject 13 | PowerShell\PublishCloudService.ps1 = PowerShell\PublishCloudService.ps1 14 | EndProjectSection 15 | EndProject 16 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{9D330DCB-F771-4959-A7C5-053D4FBC313B}" 17 | ProjectSection(SolutionItems) = preProject 18 | .nuget\NuGet.Config = .nuget\NuGet.Config 19 | .nuget\NuGet.exe = .nuget\NuGet.exe 20 | .nuget\NuGet.targets = .nuget\NuGet.targets 21 | EndProjectSection 22 | EndProject 23 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Devbridge.BasicAuthentication", "Devbridge.BasicAuthentication\Devbridge.BasicAuthentication.csproj", "{8B8D3FF3-9E4B-48D9-8BEF-52AB2651638A}" 24 | EndProject 25 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Devbridge.BasicAuthentication.Test", "Devbridge.BasicAuthentication.Test\Devbridge.BasicAuthentication.Test.csproj", "{11EBC198-765A-4017-9091-CCD5D934015A}" 26 | EndProject 27 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Devbridge.BackupDatabaseServer", "Devbridge.BackupDatabaseServer\Devbridge.BackupDatabaseServer.csproj", "{E27C9B4E-C2D9-41AD-AF13-2E02A82560FD}" 28 | EndProject 29 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Devbridge.BackupDatabaseAzureStorage", "Devbridge.BackupDatabaseAzureStorage\Devbridge.BackupDatabaseAzureStorage.csproj", "{B3C134F6-E768-4C55-B11F-717214AC500D}" 30 | EndProject 31 | Global 32 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 33 | Debug|Any CPU = Debug|Any CPU 34 | Release|Any CPU = Release|Any CPU 35 | EndGlobalSection 36 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 37 | {8B8D3FF3-9E4B-48D9-8BEF-52AB2651638A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 38 | {8B8D3FF3-9E4B-48D9-8BEF-52AB2651638A}.Debug|Any CPU.Build.0 = Debug|Any CPU 39 | {8B8D3FF3-9E4B-48D9-8BEF-52AB2651638A}.Release|Any CPU.ActiveCfg = Release|Any CPU 40 | {8B8D3FF3-9E4B-48D9-8BEF-52AB2651638A}.Release|Any CPU.Build.0 = Release|Any CPU 41 | {11EBC198-765A-4017-9091-CCD5D934015A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 42 | {11EBC198-765A-4017-9091-CCD5D934015A}.Debug|Any CPU.Build.0 = Debug|Any CPU 43 | {11EBC198-765A-4017-9091-CCD5D934015A}.Release|Any CPU.ActiveCfg = Release|Any CPU 44 | {11EBC198-765A-4017-9091-CCD5D934015A}.Release|Any CPU.Build.0 = Release|Any CPU 45 | {E27C9B4E-C2D9-41AD-AF13-2E02A82560FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 46 | {E27C9B4E-C2D9-41AD-AF13-2E02A82560FD}.Debug|Any CPU.Build.0 = Debug|Any CPU 47 | {E27C9B4E-C2D9-41AD-AF13-2E02A82560FD}.Release|Any CPU.ActiveCfg = Release|Any CPU 48 | {E27C9B4E-C2D9-41AD-AF13-2E02A82560FD}.Release|Any CPU.Build.0 = Release|Any CPU 49 | {B3C134F6-E768-4C55-B11F-717214AC500D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 50 | {B3C134F6-E768-4C55-B11F-717214AC500D}.Debug|Any CPU.Build.0 = Debug|Any CPU 51 | {B3C134F6-E768-4C55-B11F-717214AC500D}.Release|Any CPU.ActiveCfg = Release|Any CPU 52 | {B3C134F6-E768-4C55-B11F-717214AC500D}.Release|Any CPU.Build.0 = Release|Any CPU 53 | EndGlobalSection 54 | GlobalSection(SolutionProperties) = preSolution 55 | HideSolutionNode = FALSE 56 | EndGlobalSection 57 | EndGlobal 58 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | https://ch1prod-dacsvc.azure.com/DACWebService.svc 38 | 39 | 40 | Webtype 41 | 42 | 43 | https://{2}.blob.core.windows.net/{3}/{0}/{0}-{1:yyyy-MM-dd-hh-mm-ss-fff}.bacpac 44 | 45 | 46 | webtype 47 | 48 | 49 | databasebackups 50 | 51 | 52 | 3 53 | 54 | 55 | [StorageAccessKey] 56 | 57 | 58 | [Password] 59 | 60 | 61 | 62 | 64 | WebtypeLogs 65 | Webtype 66 | 67 | 68 | 69 | 70 | asadasdv.database.windows.net 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/Devbridge.BackupDatabaseAzureStorage.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B3C134F6-E768-4C55-B11F-717214AC500D} 8 | Exe 9 | Properties 10 | Devbridge.BackupDatabaseAzureStorage 11 | Devbridge.BackupDatabaseAzureStorage 12 | v4.5 13 | 512 14 | ..\ 15 | true 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | ..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll 39 | 40 | 41 | ..\packages\Common.Logging.NLog.2.0.0\lib\2.0\Common.Logging.NLog.dll 42 | 43 | 44 | False 45 | ..\packages\Microsoft.Data.Edm.5.0.2\lib\net40\Microsoft.Data.Edm.dll 46 | 47 | 48 | False 49 | ..\packages\Microsoft.Data.OData.5.0.2\lib\net40\Microsoft.Data.OData.dll 50 | 51 | 52 | ..\packages\Microsoft.WindowsAzure.ConfigurationManager.1.8.0.0\lib\net35-full\Microsoft.WindowsAzure.Configuration.dll 53 | 54 | 55 | ..\packages\WindowsAzure.Storage.2.0.3.0\lib\net40\Microsoft.WindowsAzure.Storage.dll 56 | 57 | 58 | ..\packages\NLog.2.0.0.2000\lib\net40\NLog.dll 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | False 67 | ..\packages\System.Spatial.5.0.2\lib\net40\System.Spatial.dll 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | True 83 | True 84 | Settings.settings 85 | 86 | 87 | True 88 | True 89 | Reference.svcmap 90 | 91 | 92 | 93 | 94 | 95 | PreserveNewest 96 | 97 | 98 | 99 | SettingsSingleFileGenerator 100 | Settings.Designer.cs 101 | 102 | 103 | Reference.svcmap 104 | 105 | 106 | 107 | Designer 108 | 109 | 110 | 111 | Designer 112 | 113 | 114 | Designer 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | WCF Proxy Generator 132 | Reference.cs 133 | 134 | 135 | 136 | 137 | 144 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/ExportFacade.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using Common.Logging; 5 | using Devbridge.BackupDatabaseAzureStorage.Properties; 6 | using Microsoft.WindowsAzure.Storage; 7 | using Microsoft.WindowsAzure.Storage.Auth; 8 | using Microsoft.WindowsAzure.Storage.Blob; 9 | 10 | namespace Devbridge.BackupDatabaseAzureStorage 11 | { 12 | public class ExportFacade 13 | { 14 | private readonly ILog logger = LogManager.GetCurrentClassLogger(); 15 | 16 | public void Export(string databaseName) 17 | { 18 | var ieHelper = new ImportExportHelper(); 19 | 20 | //Set Inputs to the REST Requests in the helper class 21 | ieHelper.EndPointUri = Settings.Default.DACWebServiceUrl; 22 | ieHelper.ServerName = Settings.Default.DatabaseServerName; 23 | ieHelper.StorageKey = Settings.Default.StorageAccessKey; 24 | ieHelper.DatabaseName = databaseName; 25 | ieHelper.UserName = Settings.Default.DatabaseUserName; 26 | ieHelper.Password = Settings.Default.DatabaseUserPassword; 27 | } 28 | 29 | public void ExportDatabases(IList allDatabases) 30 | { 31 | foreach (var dbName in allDatabases) 32 | { 33 | logger.InfoFormat("Export of database '{0}' started", dbName); 34 | try 35 | { 36 | Export(dbName); 37 | logger.InfoFormat("Export of database '{0}' finished succesfully", dbName); 38 | } 39 | catch (Exception ex) 40 | { 41 | logger.ErrorFormat("Error occured while exporting database '{0}'", ex, dbName); 42 | } 43 | } 44 | } 45 | 46 | public void CleanupOlderBackups() 47 | { 48 | logger.Info("CleanupOlderBackups started"); 49 | var storageAccount = new CloudStorageAccount( 50 | new StorageCredentials(Settings.Default.StorageName, Settings.Default.StorageAccessKey), 51 | true); 52 | var blobClient = storageAccount.CreateCloudBlobClient(); 53 | var container = blobClient.GetContainerReference(Settings.Default.BackupsContainer); 54 | var filesToKeep = Settings.Default.BackupFilesToKeep; 55 | try 56 | { 57 | var databaseDirs = container.ListBlobs(); 58 | foreach (var item in databaseDirs) 59 | { 60 | if (item.GetType() == typeof(CloudBlobDirectory)) 61 | { 62 | var directory = (CloudBlobDirectory)item; 63 | var databaseBackups = directory.ListBlobs(); 64 | 65 | var filesToDelete = databaseBackups.Where(b => b is CloudBlockBlob).Cast() 66 | .OrderByDescending(fi => fi.Properties.LastModified).Skip(filesToKeep); 67 | 68 | foreach (var fileToDelete in filesToDelete) 69 | { 70 | try 71 | { 72 | logger.InfoFormat("Deleting: {0}", fileToDelete.Name); 73 | fileToDelete.Delete(); 74 | } 75 | catch (Exception ex) 76 | { 77 | logger.ErrorFormat("Error occured while deleting file '{0}'", ex, fileToDelete.Uri); 78 | } 79 | } 80 | } 81 | } 82 | 83 | //var backupDir = Settings.Default.BackupsDir; 84 | //var filesToKeep = Settings.Default.BackupFilesToKeep; 85 | 86 | //var dbSubfolders = Directory.GetDirectories(backupDir); 87 | //foreach (var dbDir in dbSubfolders) 88 | //{ 89 | // var di = new DirectoryInfo(dbDir); 90 | // var backupFileInfos = di.GetFileSystemInfos("*." + BackupFileExtension); 91 | // if (backupFileInfos.Length > filesToKeep) 92 | // { 93 | // var filesToDelete = backupFileInfos.OrderByDescending(fi => fi.CreationTime).Skip(filesToKeep); 94 | // foreach (var fileToDelete in filesToDelete) 95 | // { 96 | // try 97 | // { 98 | // File.Delete(fileToDelete.FullName); 99 | // } 100 | // catch (Exception ex) 101 | // { 102 | // logger.ErrorFormat("Error occured while deleting file '{0}'", ex, fileToDelete.FullName); 103 | // } 104 | // } 105 | // } 106 | //} 107 | 108 | logger.Info("CleanupOlderBackups finished"); 109 | } 110 | catch (Exception ex) 111 | { 112 | logger.Error("Error occured in CleanupOlderBackups", ex); 113 | throw; 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/ImportExportHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Runtime.Serialization; 7 | using System.Threading; 8 | using System.Web; 9 | using System.Xml; 10 | using Common.Logging; 11 | using Devbridge.BackupDatabaseAzureStorage.DACWebService; 12 | 13 | namespace Devbridge.BackupDatabaseAzureStorage 14 | { 15 | public class ImportExportHelper 16 | { 17 | private readonly ILog logger = LogManager.GetCurrentClassLogger(); 18 | 19 | public string EndPointUri { get; set; } 20 | public string StorageKey { get; set; } 21 | public string BlobUri { get; set; } 22 | public string ServerName { get; set; } 23 | public string DatabaseName { get; set; } 24 | public string UserName { get; set; } 25 | public string Password { get; set; } 26 | 27 | public ImportExportHelper() 28 | { 29 | EndPointUri = ""; 30 | ServerName = ""; 31 | StorageKey = ""; 32 | DatabaseName = ""; 33 | UserName = ""; 34 | Password = ""; 35 | } 36 | 37 | public string DoExport(string blobUri) 38 | { 39 | logger.Info(String.Format("Starting Export Operation - {0}\n\r", DateTime.Now)); 40 | string requestGuid = null; 41 | bool exportComplete = false; 42 | string exportedBlobPath = null; 43 | 44 | //Setup Web Request for Export Operation 45 | WebRequest webRequest = WebRequest.Create(this.EndPointUri + @"/Export"); 46 | webRequest.Method = WebRequestMethods.Http.Post; 47 | webRequest.ContentType = @"application/xml"; 48 | 49 | //Create Web Request Inputs - Blob Storage Credentials and Server Connection Info 50 | ExportInput exportInputs = new ExportInput 51 | { 52 | BlobCredentials = new BlobStorageAccessKeyCredentials 53 | { 54 | StorageAccessKey = this.StorageKey, 55 | Uri = String.Format(blobUri, this.DatabaseName, DateTime.UtcNow.Ticks.ToString()) 56 | }, 57 | ConnectionInfo = new ConnectionInfo 58 | { 59 | ServerName = this.ServerName, 60 | DatabaseName = this.DatabaseName, 61 | UserName = this.UserName, 62 | Password = this.Password 63 | } 64 | }; 65 | 66 | //Perform Web Request 67 | logger.Info("Making Web Request For Export Operation..."); 68 | Stream webRequestStream = webRequest.GetRequestStream(); 69 | DataContractSerializer dataContractSerializer = new DataContractSerializer(exportInputs.GetType()); 70 | dataContractSerializer.WriteObject(webRequestStream, exportInputs); 71 | webRequestStream.Close(); 72 | 73 | //Get Response and Extract Request Identifier 74 | logger.Info("Reading Response and extracting Export Request Identifier..."); 75 | WebResponse webResponse = null; 76 | XmlReader xmlStreamReader = null; 77 | 78 | try 79 | { 80 | //Initialize the WebResponse to the response from the WebRequest 81 | webResponse = webRequest.GetResponse(); 82 | 83 | xmlStreamReader = XmlReader.Create(webResponse.GetResponseStream()); 84 | xmlStreamReader.ReadToFollowing("guid"); 85 | requestGuid = xmlStreamReader.ReadElementContentAsString(); 86 | logger.Info(String.Format("Your Export Request Guid is: {0}", requestGuid)); 87 | 88 | //Get Export Operation Status 89 | while (!exportComplete) 90 | { 91 | logger.Info("Checking export status..."); 92 | List statusInfoList = CheckRequestStatus(requestGuid); 93 | StatusInfo statusInfo = statusInfoList.FirstOrDefault(); 94 | logger.Info(statusInfo.Status); 95 | 96 | if (statusInfo.Status == "Failed") 97 | { 98 | logger.Info(String.Format("Database export failed: {0}", statusInfo.ErrorMessage)); 99 | exportComplete = true; 100 | } 101 | 102 | if (statusInfo.Status == "Completed") 103 | { 104 | exportedBlobPath = statusInfo.BlobUri; 105 | logger.Info(String.Format("Export Complete - Database exported to: {0}\n\r", exportedBlobPath)); 106 | exportComplete = true; 107 | } 108 | 109 | if (!exportComplete) 110 | { 111 | Thread.Sleep(3000); 112 | } 113 | } 114 | 115 | return exportedBlobPath; 116 | } 117 | catch (WebException responseException) 118 | { 119 | logger.ErrorFormat("Request Falied:{0}", responseException,responseException.Message); 120 | if (responseException.Response != null) 121 | { 122 | logger.ErrorFormat("Status Code: {0}", ((HttpWebResponse)responseException.Response).StatusCode); 123 | logger.ErrorFormat("Status Description: {0}\n\r", ((HttpWebResponse)responseException.Response).StatusDescription); 124 | } 125 | return null; 126 | } 127 | } 128 | 129 | public bool DoImport(string blobUri) 130 | { 131 | logger.Info(String.Format("Starting Import Operation - {0}\n\r", DateTime.Now)); 132 | string requestGuid = null; 133 | bool importComplete = false; 134 | 135 | //Setup Web Request for Import Operation 136 | WebRequest webRequest = WebRequest.Create(this.EndPointUri + @"/Import"); 137 | webRequest.Method = WebRequestMethods.Http.Post; 138 | webRequest.ContentType = @"application/xml"; 139 | 140 | //Create Web Request Inputs - Database Size & Edition, Blob Store Credentials and Server Connection Info 141 | ImportInput importInputs = new ImportInput 142 | { 143 | AzureEdition = "Web", 144 | DatabaseSizeInGB = 1, 145 | BlobCredentials = new BlobStorageAccessKeyCredentials 146 | { 147 | StorageAccessKey = this.StorageKey, 148 | Uri = String.Format(blobUri, this.DatabaseName, DateTime.UtcNow.Ticks.ToString()) 149 | }, 150 | ConnectionInfo = new ConnectionInfo 151 | { 152 | ServerName = this.ServerName, 153 | DatabaseName = this.DatabaseName, 154 | UserName = this.UserName, 155 | Password = this.Password 156 | } 157 | }; 158 | 159 | //Perform Web Request 160 | logger.Info("Making Web Request for Import Operation..."); 161 | Stream webRequestStream = webRequest.GetRequestStream(); 162 | DataContractSerializer dataContractSerializer = new DataContractSerializer(importInputs.GetType()); 163 | dataContractSerializer.WriteObject(webRequestStream, importInputs); 164 | webRequestStream.Close(); 165 | 166 | //Get Response and Extract Request Identifier 167 | logger.Info("Serializing response and extracting guid..."); 168 | WebResponse webResponse = null; 169 | XmlReader xmlStreamReader = null; 170 | 171 | try 172 | { 173 | //Initialize the WebResponse to the response from the WebRequest 174 | webResponse = webRequest.GetResponse(); 175 | 176 | xmlStreamReader = XmlReader.Create(webResponse.GetResponseStream()); 177 | xmlStreamReader.ReadToFollowing("guid"); 178 | requestGuid = xmlStreamReader.ReadElementContentAsString(); 179 | logger.Info(String.Format("Request Guid: {0}", requestGuid)); 180 | 181 | //Get Status of Import Operation 182 | while (!importComplete) 183 | { 184 | logger.Info("Checking status of Import..."); 185 | List statusInfoList = CheckRequestStatus(requestGuid); 186 | StatusInfo statusInfo = statusInfoList.FirstOrDefault(); 187 | logger.Info(statusInfo.Status); 188 | 189 | if (statusInfo.Status == "Failed") 190 | { 191 | logger.Info(String.Format("Database import failed: {0}", statusInfo.ErrorMessage)); 192 | importComplete = true; 193 | } 194 | 195 | if (statusInfo.Status == "Completed") 196 | { 197 | logger.Info(String.Format("Import Complete - Database imported to: {0}\n\r", statusInfo.DatabaseName)); 198 | importComplete = true; 199 | } 200 | } 201 | 202 | return importComplete; 203 | } 204 | catch (WebException responseException) 205 | { 206 | logger.ErrorFormat("Request Falied: {0}",responseException, responseException.Message); 207 | { 208 | logger.ErrorFormat("Status Code: {0}", ((HttpWebResponse)responseException.Response).StatusCode); 209 | logger.ErrorFormat("Status Description: {0}\n\r", ((HttpWebResponse)responseException.Response).StatusDescription); 210 | } 211 | 212 | return importComplete; 213 | } 214 | } 215 | 216 | public List CheckRequestStatus(string requestGuid) 217 | { 218 | WebRequest webRequest = WebRequest.Create(this.EndPointUri + string.Format("/Status?servername={0}&username={1}&password={2}&reqId={3}", 219 | HttpUtility.UrlEncode(this.ServerName), 220 | HttpUtility.UrlEncode(this.UserName), 221 | HttpUtility.UrlEncode(this.Password), 222 | HttpUtility.UrlEncode(requestGuid))); 223 | 224 | webRequest.Method = WebRequestMethods.Http.Get; 225 | webRequest.ContentType = @"application/xml"; 226 | WebResponse webResponse = webRequest.GetResponse(); 227 | XmlReader xmlStreamReader = XmlReader.Create(webResponse.GetResponseStream()); 228 | DataContractSerializer dataContractSerializer = new DataContractSerializer(typeof(List)); 229 | 230 | return (List)dataContractSerializer.ReadObject(xmlStreamReader, true); 231 | } 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/NLog.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/Program.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Devbridge.BackupDatabaseAzureStorage.Properties; 3 | 4 | namespace Devbridge.BackupDatabaseAzureStorage 5 | { 6 | class Program 7 | { 8 | static void Main(string[] args) 9 | { 10 | var exportFacade = new ExportFacade(); 11 | exportFacade.ExportDatabases(Settings.Default.BackupedDatabases.Cast().ToList()); 12 | exportFacade.CleanupOlderBackups(); 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Devbridge.BackupDatabaseAzureStorage")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Devbridge.BackupDatabaseAzureStorage")] 13 | [assembly: AssemblyCopyright("Copyright © 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("8aa70feb-fcb9-408e-bd0b-ccc22a926c12")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.18034 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Devbridge.BackupDatabaseAzureStorage.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | 26 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 28 | [global::System.Configuration.DefaultSettingValueAttribute("https://ch1prod-dacsvc.azure.com/DACWebService.svc")] 29 | public string DACWebServiceUrl { 30 | get { 31 | return ((string)(this["DACWebServiceUrl"])); 32 | } 33 | } 34 | 35 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 36 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 37 | [global::System.Configuration.DefaultSettingValueAttribute("Webtype")] 38 | public string DatabaseUserName { 39 | get { 40 | return ((string)(this["DatabaseUserName"])); 41 | } 42 | } 43 | 44 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 45 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 46 | [global::System.Configuration.DefaultSettingValueAttribute("https://{2}.blob.core.windows.net/{3}/{0}/{0}-{1:yyyy-MM-dd-hh-mm-ss-fff}.bacpac")] 47 | public string ExportFileNameFormat { 48 | get { 49 | return ((string)(this["ExportFileNameFormat"])); 50 | } 51 | } 52 | 53 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 54 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 55 | [global::System.Configuration.DefaultSettingValueAttribute("webtype")] 56 | public string StorageName { 57 | get { 58 | return ((string)(this["StorageName"])); 59 | } 60 | } 61 | 62 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 63 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 64 | [global::System.Configuration.DefaultSettingValueAttribute("databasebackups")] 65 | public string BackupsContainer { 66 | get { 67 | return ((string)(this["BackupsContainer"])); 68 | } 69 | } 70 | 71 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 72 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 73 | [global::System.Configuration.DefaultSettingValueAttribute("3")] 74 | public int BackupFilesToKeep { 75 | get { 76 | return ((int)(this["BackupFilesToKeep"])); 77 | } 78 | } 79 | 80 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 81 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 82 | [global::System.Configuration.DefaultSettingValueAttribute("[StorageAccessKey]")] 83 | public string StorageAccessKey { 84 | get { 85 | return ((string)(this["StorageAccessKey"])); 86 | } 87 | } 88 | 89 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 90 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 91 | [global::System.Configuration.DefaultSettingValueAttribute("[Password]")] 92 | public string DatabaseUserPassword { 93 | get { 94 | return ((string)(this["DatabaseUserPassword"])); 95 | } 96 | } 97 | 98 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 99 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 100 | [global::System.Configuration.DefaultSettingValueAttribute("\r\n\r\n WebtypeLogs\r\n Webtype\r\n")] 103 | public global::System.Collections.Specialized.StringCollection BackupedDatabases { 104 | get { 105 | return ((global::System.Collections.Specialized.StringCollection)(this["BackupedDatabases"])); 106 | } 107 | } 108 | 109 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 110 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 111 | [global::System.Configuration.DefaultSettingValueAttribute("asadasdv.database.windows.net")] 112 | public string DatabaseServerName { 113 | get { 114 | return ((string)(this["DatabaseServerName"])); 115 | } 116 | } 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | https://ch1prod-dacsvc.azure.com/DACWebService.svc 7 | 8 | 9 | Webtype 10 | 11 | 12 | https://{2}.blob.core.windows.net/{3}/{0}/{0}-{1:yyyy-MM-dd-hh-mm-ss-fff}.bacpac 13 | 14 | 15 | webtype 16 | 17 | 18 | databasebackups 19 | 20 | 21 | 3 22 | 23 | 24 | [StorageAccessKey] 25 | 26 | 27 | [Password] 28 | 29 | 30 | <?xml version="1.0" encoding="utf-16"?> 31 | <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 32 | <string>WebtypeLogs</string> 33 | <string>Webtype</string> 34 | </ArrayOfString> 35 | 36 | 37 | asadasdv.database.windows.net 38 | 39 | 40 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/Service References/DACWebService/Devbridge.BackupDatabaseAzureStorage.DACWebService.StatusInfo.datasource: -------------------------------------------------------------------------------- 1 |  2 | 8 | 9 | Devbridge.BackupDatabaseAzureStorage.DACWebService.StatusInfo, Service References.DACWebService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null 10 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/Service References/DACWebService/Microsoft.SqlServer.Management.Dac.ServiceTypes.xsd: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/Service References/DACWebService/Microsoft.SqlServer.Management.Dac.Services.wsdl: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/Service References/DACWebService/Reference.svcmap: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | true 6 | true 7 | 8 | false 9 | false 10 | false 11 | 12 | 13 | true 14 | Auto 15 | true 16 | true 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/Service References/DACWebService/configuration.svcinfo: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/Service References/DACWebService/configuration91.svcinfo: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/Service References/DACWebService/service.wsdl: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/Service References/DACWebService/service.xsd: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/Service References/DACWebService/service1.xsd: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseAzureStorage/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | DatabaseBackups 29 | 30 | 31 | 14 32 | 33 | 34 | {0}_{1:yyyy-MM-dd_hh-mm-ss-fff} 35 | 36 | 37 | 38 | 39 | TestBackup 40 | 41 | 42 | 43 | 44 | Webtype 45 | 46 | 47 | tcp:sdasadasfg.database.windows.net 48 | 49 | 50 | [Password] 51 | 52 | 53 | DefaultEndpointsProtocol=https;AccountName=webtype;AccountKey=[ACCOUNTKEY] 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/Devbridge.BackupDatabaseServer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {E27C9B4E-C2D9-41AD-AF13-2E02A82560FD} 8 | Exe 9 | Properties 10 | Devbridge.BackupDatabaseServer 11 | Devbridge.BackupDatabaseServer 12 | v4.0 13 | 512 14 | 15 | ..\ 16 | true 17 | 18 | 19 | AnyCPU 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | 28 | 29 | AnyCPU 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | 39 | ..\packages\Common.Logging.2.1.2\lib\net40\Common.Logging.dll 40 | 41 | 42 | ..\packages\Common.Logging.NLog.2.0.0\lib\2.0\Common.Logging.NLog.dll 43 | 44 | 45 | False 46 | ..\packages\Microsoft.Data.Edm.5.0.2\lib\net40\Microsoft.Data.Edm.dll 47 | 48 | 49 | False 50 | ..\packages\Microsoft.Data.OData.5.0.2\lib\net40\Microsoft.Data.OData.dll 51 | 52 | 53 | ..\packages\Microsoft.SqlServer.Dac.1.0.1\lib\Microsoft.Data.Tools.Schema.Sql.dll 54 | True 55 | 56 | 57 | ..\packages\Microsoft.SqlServer.Dac.1.0.1\lib\Microsoft.Data.Tools.Utilities.dll 58 | True 59 | 60 | 61 | ..\packages\Microsoft.SqlServer.Dac.1.0.1\lib\Microsoft.SqlServer.Dac.dll 62 | True 63 | 64 | 65 | ..\packages\Microsoft.WindowsAzure.ConfigurationManager.1.8.0.0\lib\net35-full\Microsoft.WindowsAzure.Configuration.dll 66 | 67 | 68 | ..\packages\WindowsAzure.Storage.2.0.3.0\lib\net40\Microsoft.WindowsAzure.Storage.dll 69 | 70 | 71 | ..\packages\NLog.2.0.0.2000\lib\net40\NLog.dll 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | False 80 | ..\packages\System.Spatial.5.0.2\lib\net40\System.Spatial.dll 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | True 94 | True 95 | Settings.settings 96 | 97 | 98 | True 99 | True 100 | Reference.svcmap 101 | 102 | 103 | 104 | 105 | Designer 106 | 107 | 108 | PreserveNewest 109 | 110 | 111 | 112 | SettingsSingleFileGenerator 113 | Settings.Designer.cs 114 | 115 | 116 | Reference.svcmap 117 | 118 | 119 | 120 | Designer 121 | 122 | 123 | 124 | Designer 125 | 126 | 127 | Designer 128 | 129 | 130 | 131 | 132 | 133 | WCF Proxy Generator 134 | Reference.cs 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 154 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/ExportFacade.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Data.SqlClient; 5 | using System.IO; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | using Common.Logging; 10 | using Devbridge.BackupDatabaseServer.Properties; 11 | using Microsoft.SqlServer.Dac; 12 | 13 | namespace Devbridge.BackupDatabaseServer 14 | { 15 | public class ExportFacade 16 | { 17 | private SqlConnection connection; 18 | private string connectionString; 19 | private readonly ILog logger = LogManager.GetCurrentClassLogger(); 20 | private const string BackupFileExtension = "bacpac"; 21 | 22 | public ExportFacade(string connectionString) 23 | { 24 | this.connectionString = connectionString; 25 | this.connection = new SqlConnection(connectionString); 26 | } 27 | 28 | public void Export(string databaseName, string targetFilename) 29 | { 30 | DacServices dacServices = new DacServices(connectionString); 31 | 32 | dacServices.ExportBacpac(targetFilename, databaseName); 33 | } 34 | 35 | public void ExportAllDatabases() 36 | { 37 | logger.Info("ExportAllDatabases started"); 38 | try 39 | { 40 | IList allDatabases = null; 41 | OpenConnection(); 42 | try 43 | { 44 | allDatabases = GetServerDatabases(); 45 | } 46 | finally 47 | { 48 | CloseConnection(); 49 | } 50 | 51 | allDatabases = allDatabases.Where(db => db == "TestBackup").ToList(); 52 | 53 | ExportDatabases(allDatabases); 54 | 55 | logger.Info("ExportAllDatabases finished"); 56 | } 57 | catch (Exception ex) 58 | { 59 | logger.Error("Error occured in ExportAllDatabases", ex); 60 | throw ex; 61 | } 62 | } 63 | 64 | public void ExportDatabases(IList allDatabases) 65 | { 66 | foreach (var dbName in allDatabases) 67 | { 68 | string backupDir = Path.Combine(Settings.Default.BackupsDir, dbName); 69 | if (!Directory.Exists(backupDir)) 70 | { 71 | Directory.CreateDirectory(backupDir); 72 | } 73 | 74 | string fileName = Path.Combine(backupDir, string.Format(Settings.Default.FileNameFormat, dbName, DateTime.Now) + "." + BackupFileExtension); 75 | 76 | logger.InfoFormat("Export of database '{0}' started", dbName); 77 | try 78 | { 79 | Export(dbName, fileName); 80 | logger.InfoFormat("Export of database '{0}' finished succesfully", dbName); 81 | } 82 | catch (Exception ex) 83 | { 84 | logger.ErrorFormat("Error occured while exporting database '{0}'", ex, dbName); 85 | } 86 | } 87 | } 88 | 89 | public void CleanupOlderBackups() 90 | { 91 | logger.Info("CleanupOlderBackups started"); 92 | try 93 | { 94 | var backupDir = Settings.Default.BackupsDir; 95 | var filesToKeep = Settings.Default.BackupFilesToKeep; 96 | 97 | var dbSubfolders = Directory.GetDirectories(backupDir); 98 | foreach (var dbDir in dbSubfolders) 99 | { 100 | var di = new DirectoryInfo(dbDir); 101 | var backupFileInfos = di.GetFileSystemInfos("*." + BackupFileExtension); 102 | if (backupFileInfos.Length > filesToKeep) 103 | { 104 | var filesToDelete = backupFileInfos.OrderByDescending(fi => fi.CreationTime).Skip(filesToKeep); 105 | foreach (var fileToDelete in filesToDelete) 106 | { 107 | try 108 | { 109 | File.Delete(fileToDelete.FullName); 110 | } 111 | catch (Exception ex) 112 | { 113 | logger.ErrorFormat("Error occured while deleting file '{0}'", ex, fileToDelete.FullName); 114 | } 115 | } 116 | } 117 | } 118 | 119 | logger.Info("CleanupOlderBackups finished"); 120 | } 121 | catch (Exception ex) 122 | { 123 | logger.Error("Error occured in CleanupOlderBackups", ex); 124 | throw ex; 125 | } 126 | } 127 | 128 | private void OpenConnection() 129 | { 130 | this.connection.Open(); 131 | } 132 | 133 | private void CloseConnection() 134 | { 135 | this.connection.Close(); 136 | } 137 | 138 | private IList GetServerDatabases() 139 | { 140 | SqlDataAdapter adapter = new SqlDataAdapter("select name from sys.databases where state_desc='ONLINE' and name<>'master'", connection); 141 | 142 | DataTable dt = new DataTable(); 143 | adapter.Fill(dt); 144 | 145 | return dt.AsEnumerable().Select(row => row[0] as string).ToList(); 146 | } 147 | 148 | private void BackupDatabase(string sourceDatabaseName, string targetDatabaseName) 149 | { 150 | SqlCommand backupCommand = new SqlCommand("CREATE DATABASE @targetDB AS COPY OF @sourceDB", connection); 151 | backupCommand.Parameters.AddWithValue("@sourceDB", sourceDatabaseName); 152 | backupCommand.Parameters.AddWithValue("@targetDB", targetDatabaseName); 153 | backupCommand.ExecuteNonQuery(); 154 | } 155 | 156 | 157 | //public bool CheckIfBackupDatabaseFinishedSuccessfully(string databaseName) 158 | //{ 159 | // SqlCommand backupCommand = new SqlCommand("SELECT state_desc FROM sys.databases WHERE name = @db", connection); 160 | // backupCommand.Parameters.AddWithValue("@db", databaseName); 161 | // backupCommand.ExecuteNonQuery(); 162 | //} 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/NLog.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Devbridge.BackupDatabaseServer.Properties; 7 | 8 | namespace Devbridge.BackupDatabaseServer 9 | { 10 | class Program 11 | { 12 | static void Main(string[] args) 13 | { 14 | var exportFacade = new ExportFacade(Settings.Default.ConnectionString); 15 | if (Settings.Default.BackupedDatabases != null && Settings.Default.BackupedDatabases.Count > 0) 16 | { 17 | exportFacade.ExportDatabases(Settings.Default.BackupedDatabases.Cast().ToList()); 18 | } 19 | else 20 | { 21 | exportFacade.ExportAllDatabases(); 22 | } 23 | 24 | exportFacade.CleanupOlderBackups(); 25 | 26 | 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Devbridge.BackupDatabaseServer")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Devbridge.BackupDatabaseServer")] 13 | [assembly: AssemblyCopyright("Copyright © 2012")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("7885c6bb-e66f-456f-b6b6-e4507d101cb9")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.18034 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Devbridge.BackupDatabaseServer.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | 26 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 28 | [global::System.Configuration.DefaultSettingValueAttribute("DatabaseBackups")] 29 | public string BackupsDir { 30 | get { 31 | return ((string)(this["BackupsDir"])); 32 | } 33 | } 34 | 35 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 36 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 37 | [global::System.Configuration.DefaultSettingValueAttribute("14")] 38 | public int BackupFilesToKeep { 39 | get { 40 | return ((int)(this["BackupFilesToKeep"])); 41 | } 42 | } 43 | 44 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 45 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 46 | [global::System.Configuration.DefaultSettingValueAttribute("{0}_{1:yyyy-MM-dd_hh-mm-ss-fff}")] 47 | public string FileNameFormat { 48 | get { 49 | return ((string)(this["FileNameFormat"])); 50 | } 51 | } 52 | 53 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 54 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 55 | [global::System.Configuration.DefaultSettingValueAttribute("\r\n\r\n TestBackup\r\n")] 58 | public global::System.Collections.Specialized.StringCollection BackupedDatabases { 59 | get { 60 | return ((global::System.Collections.Specialized.StringCollection)(this["BackupedDatabases"])); 61 | } 62 | } 63 | 64 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 65 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 66 | [global::System.Configuration.DefaultSettingValueAttribute("Webtype")] 67 | public string BlobDBUserName { 68 | get { 69 | return ((string)(this["BlobDBUserName"])); 70 | } 71 | } 72 | 73 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 74 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 75 | [global::System.Configuration.DefaultSettingValueAttribute("tcp:sdasadasfg.database.windows.net")] 76 | public string BlobDBServerName { 77 | get { 78 | return ((string)(this["BlobDBServerName"])); 79 | } 80 | } 81 | 82 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 83 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 84 | [global::System.Configuration.DefaultSettingValueAttribute("[Password]")] 85 | public string BlogDBUserPsw { 86 | get { 87 | return ((string)(this["BlogDBUserPsw"])); 88 | } 89 | } 90 | 91 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 92 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 93 | [global::System.Configuration.DefaultSettingValueAttribute("DefaultEndpointsProtocol=https;AccountName=webtype;AccountKey=[ACCOUNTKEY]")] 94 | public string BlobConnectionString { 95 | get { 96 | return ((string)(this["BlobConnectionString"])); 97 | } 98 | } 99 | 100 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 101 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 102 | [global::System.Configuration.SpecialSettingAttribute(global::System.Configuration.SpecialSetting.ConnectionString)] 103 | [global::System.Configuration.DefaultSettingValueAttribute("Data Source=tcp:asdasdasd.database.windows.net,1433;Integrated Security=False;Use" + 104 | "r ID=[UserId];Password=[Password];Connect Timeout=15;Encrypt=False;TrustServerCe" + 105 | "rtificate=False")] 106 | public string ConnectionString { 107 | get { 108 | return ((string)(this["ConnectionString"])); 109 | } 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | DatabaseBackups 7 | 8 | 9 | 14 10 | 11 | 12 | {0}_{1:yyyy-MM-dd_hh-mm-ss-fff} 13 | 14 | 15 | <?xml version="1.0" encoding="utf-16"?> 16 | <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 17 | <string>TestBackup</string> 18 | </ArrayOfString> 19 | 20 | 21 | Webtype 22 | 23 | 24 | tcp:sdasadasfg.database.windows.net 25 | 26 | 27 | [Password] 28 | 29 | 30 | DefaultEndpointsProtocol=https;AccountName=webtype;AccountKey=[ACCOUNTKEY] 31 | 32 | 33 | <?xml version="1.0" encoding="utf-16"?> 34 | <SerializableConnectionString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 35 | <ConnectionString>Data Source=tcp:asdasdasd.database.windows.net,1433;Integrated Security=False;User ID=[UserId];Password=[Password];Connect Timeout=15;Encrypt=False;TrustServerCertificate=False</ConnectionString> 36 | </SerializableConnectionString> 37 | Data Source=tcp:asdasdasd.database.windows.net,1433;Integrated Security=False;User ID=[UserId];Password=[Password];Connect Timeout=15;Encrypt=False;TrustServerCertificate=False 38 | 39 | 40 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/Service References/DACWebService/Devbridge.BackupDatabaseServer.DACWebService.StatusInfo.datasource: -------------------------------------------------------------------------------- 1 |  2 | 8 | 9 | Devbridge.BackupDatabaseServer.DACWebService.StatusInfo, Service References.DACWebService.Reference.cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null 10 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/Service References/DACWebService/Microsoft.SqlServer.Management.Dac.ServiceTypes.xsd: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/Service References/DACWebService/Microsoft.SqlServer.Management.Dac.Services.wsdl: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/Service References/DACWebService/Reference.svcmap: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | true 6 | 7 | false 8 | false 9 | false 10 | 11 | 12 | 13 | 14 | true 15 | Auto 16 | true 17 | true 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/Service References/DACWebService/configuration.svcinfo: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/Service References/DACWebService/configuration91.svcinfo: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/Service References/DACWebService/service.wsdl: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/Service References/DACWebService/service.xsd: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/Service References/DACWebService/service1.xsd: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Devbridge.BackupDatabaseServer/readme.txt: -------------------------------------------------------------------------------- 1 | This project exports all database in sql azure server to some folder (produces bacpac) files. It relies on DACFramework (http://www.microsoft.com/en-us/download/details.aspx?id=35756) which must be installed in order to use this tool. 2 | We need to improve backup process by first making database copies then exporting them - because exports are not transactionally consistent. -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication.Test/Config/basicAuthentication.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication.Test/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using System.Web.Mvc; 2 | 3 | namespace Devbridge.BasicAuthentication.Test.Controllers 4 | { 5 | public class HomeController : Controller 6 | { 7 | public ActionResult Index() 8 | { 9 | return View(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication.Test/Devbridge.BasicAuthentication.Test.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | 8 | 9 | 2.0 10 | {11EBC198-765A-4017-9091-CCD5D934015A} 11 | {E53F8FEA-EAE0-44A6-8774-FFD645390401};{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} 12 | Library 13 | Properties 14 | Devbridge.BasicAuthentication.Test 15 | Devbridge.BasicAuthentication.Test 16 | v4.0 17 | false 18 | false 19 | 20 | 21 | 22 | 23 | 24 | ..\ 25 | true 26 | true 27 | 4.0 28 | 29 | 30 | true 31 | full 32 | false 33 | bin\ 34 | DEBUG;TRACE 35 | prompt 36 | 4 37 | 38 | 39 | pdbonly 40 | true 41 | bin\ 42 | TRACE 43 | prompt 44 | 4 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | True 67 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll 68 | 69 | 70 | True 71 | ..\packages\Microsoft.AspNet.WebPages.1.0.20105.408\lib\net40\System.Web.Helpers.dll 72 | 73 | 74 | True 75 | ..\packages\Microsoft.AspNet.Mvc.3.0.20105.1\lib\net40\System.Web.Mvc.dll 76 | 77 | 78 | True 79 | ..\packages\Microsoft.AspNet.Razor.1.0.20105.408\lib\net40\System.Web.Razor.dll 80 | 81 | 82 | True 83 | ..\packages\Microsoft.AspNet.WebPages.1.0.20105.408\lib\net40\System.Web.WebPages.dll 84 | 85 | 86 | True 87 | ..\packages\Microsoft.AspNet.WebPages.1.0.20105.408\lib\net40\System.Web.WebPages.Deployment.dll 88 | 89 | 90 | True 91 | ..\packages\Microsoft.AspNet.WebPages.1.0.20105.408\lib\net40\System.Web.WebPages.Razor.dll 92 | 93 | 94 | 95 | 96 | 97 | Properties\SharedAssemblyInfo.cs 98 | 99 | 100 | 101 | Global.asax 102 | 103 | 104 | 105 | 106 | 107 | 108 | Designer 109 | 110 | 111 | Web.config 112 | 113 | 114 | Web.config 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | {8b8d3ff3-9e4b-48d9-8bef-52ab2651638a} 136 | Devbridge.BasicAuthentication 137 | 138 | 139 | 140 | 10.0 141 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | True 154 | 155 | 156 | 157 | 158 | 159 | 165 | -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication.Test/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="Devbridge.BasicAuthentication.Test.MvcApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication.Test/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data.Entity; 4 | using System.Linq; 5 | using System.Web; 6 | using System.Web.Mvc; 7 | using System.Web.Routing; 8 | 9 | namespace Devbridge.BasicAuthentication.Test 10 | { 11 | // Note: For instructions on enabling IIS6 or IIS7 classic mode, 12 | // visit http://go.microsoft.com/?LinkId=9394801 13 | 14 | public class MvcApplication : System.Web.HttpApplication 15 | { 16 | public static void RegisterGlobalFilters(GlobalFilterCollection filters) 17 | { 18 | filters.Add(new HandleErrorAttribute()); 19 | } 20 | 21 | public static void RegisterRoutes(RouteCollection routes) 22 | { 23 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 24 | 25 | routes.MapRoute( 26 | "Default", // Route name 27 | "{controller}/{action}/{id}", // URL with parameters 28 | new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults 29 | ); 30 | 31 | } 32 | 33 | protected void Application_Start() 34 | { 35 | AreaRegistration.RegisterAllAreas(); 36 | 37 | RegisterGlobalFilters(GlobalFilters.Filters); 38 | RegisterRoutes(RouteTable.Routes); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication.Test/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("DevBridge.BasicAuthentication.Test")] 8 | [assembly: AssemblyDescription("")] 9 | 10 | // Setting ComVisible to false makes the types in this assembly not visible 11 | // to COM components. If you need to access a type in this assembly from 12 | // COM, set the ComVisible attribute to true on that type. 13 | [assembly: ComVisible(false)] 14 | 15 | // The following GUID is for the ID of the typelib if this project is exposed to COM 16 | [assembly: Guid("33d49b02-a8e0-48c3-ab0b-cde0f7b08326")] -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication.Test/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | ViewBag.Title = "Test page"; 3 | } 4 | 5 | This is a test page. -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication.Test/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = null; 3 | } 4 | 5 | 6 | 7 | 8 | Error 9 | 10 | 11 |

12 | Sorry, an error occurred while processing your request. 13 |

14 | 15 | -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication.Test/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | @ViewBag.Title 5 | 6 | 7 | 8 | @RenderBody() 9 | 10 | 11 | -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication.Test/Views/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 |
7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 39 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication.Test/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "~/Views/Shared/_Layout.cshtml"; 3 | } -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication.Test/Web.Debug.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication.Test/Web.Release.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication.Test/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication.Test/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication/BasicAuthenticationModule.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Text; 7 | using System.Text.RegularExpressions; 8 | using System.Web; 9 | 10 | namespace Devbridge.BasicAuthentication 11 | { 12 | /// 13 | /// This module performs basic authentication. 14 | /// For details on basic authentication see RFC 2617. 15 | /// Based on the work by Mike Volodarsky (www.iis.net/learn/develop/runtime-extensibility/developing-a-module-using-net) 16 | /// 17 | /// The basic operational flow is: 18 | /// 19 | /// On AuthenticateRequest: 20 | /// extract the basic authentication credentials 21 | /// verify the credentials 22 | /// if succesfull, create and send authentication cookie 23 | /// 24 | /// On SendResponseHeaders: 25 | /// if there is no authentication cookie in request, clear response, add unauthorized status code (401) and 26 | /// add the basic authentication challenge to trigger basic authentication. 27 | /// 28 | public class BasicAuthenticationModule : IHttpModule 29 | { 30 | /// 31 | /// HTTP1.1 Authorization header 32 | /// 33 | public const string HttpAuthorizationHeader = "Authorization"; 34 | 35 | /// 36 | /// HTTP1.1 Basic Challenge Scheme Name 37 | /// 38 | public const string HttpBasicSchemeName = "Basic"; // 39 | 40 | /// 41 | /// HTTP1.1 Credential username and password separator 42 | /// 43 | public const char HttpCredentialSeparator = ':'; 44 | 45 | /// 46 | /// HTTP1.1 Not authorized response status code 47 | /// 48 | public const int HttpNotAuthorizedStatusCode = 401; 49 | 50 | /// 51 | /// HTTP1.1 Basic Challenge Scheme Name 52 | /// 53 | public const string HttpWwwAuthenticateHeader = "WWW-Authenticate"; 54 | 55 | /// 56 | /// The name of cookie that is sent to client 57 | /// 58 | public const string AuthenticationCookieName = "BasicAuthentication"; 59 | 60 | /// 61 | /// HTTP.1.1 Basic Challenge Realm 62 | /// 63 | public const string Realm = "demo"; 64 | 65 | /// 66 | /// The App Setting that can enable/disable the entire functionality 67 | /// 68 | public const string EnabledAppSetting = "BasicAuthEnabled"; 69 | 70 | /// 71 | /// The credentials that are allowed to access the site. 72 | /// 73 | private IDictionary activeUsers; 74 | 75 | /// 76 | /// Exclude configuration - request URL is matched to dictionary key and request method is matched to the value of the same key-value pair. 77 | /// 78 | private IDictionary excludes; 79 | 80 | /// 81 | /// Indicates whether redirects are allowed without authentication. 82 | /// 83 | private bool allowRedirects; 84 | 85 | /// 86 | /// Indicates whether local requests are allowed without authentication. 87 | /// 88 | private bool allowLocal; 89 | 90 | /// 91 | /// Regular expression that matches any given string. 92 | /// 93 | private readonly static Regex AllowAnyRegex = new Regex(".*", RegexOptions.Compiled); 94 | 95 | /// 96 | /// Boolean that allows an app setting to enable/disable basic auth 97 | /// 98 | private bool isEnabled = true; 99 | 100 | /// 101 | /// Dictionary that caches whether basic authentication challenge should be sent. Key is request URL + request method, value indicates whether 102 | /// challenge should be sent. 103 | /// 104 | private static IDictionary shouldChallengeCache = new Dictionary(); 105 | 106 | public void AuthenticateUser(object source, EventArgs e) 107 | { 108 | var httpApp = (HttpApplication)source; 109 | var context = httpApp.Context; 110 | 111 | string authorizationHeader = context.Request.Headers[HttpAuthorizationHeader]; 112 | 113 | // Extract the basic authentication credentials from the request 114 | string userName = null; 115 | string password = null; 116 | if (!ExtractBasicCredentials(authorizationHeader, ref userName, ref password)) 117 | { 118 | httpApp.CompleteRequest(); 119 | return; 120 | } 121 | 122 | // Validate the user credentials 123 | if (!ValidateCredentials(userName, password)) 124 | { 125 | httpApp.CompleteRequest(); 126 | return; 127 | } 128 | 129 | // Add Header with same name as Cookie 130 | if (context.Request.Headers.AllKeys.FirstOrDefault(x => x.Equals(AuthenticationCookieName)) == null) 131 | { 132 | context.Request.Headers.Add(AuthenticationCookieName, userName); 133 | } 134 | 135 | // check whether cookie is set and send it to client if needed 136 | var authCookie = context.Request.Cookies.Get(AuthenticationCookieName); 137 | if (authCookie == null) 138 | { 139 | authCookie = new HttpCookie(AuthenticationCookieName, "1") { Expires = DateTime.Now.AddHours(1) }; 140 | context.Response.Cookies.Add(authCookie); 141 | } 142 | } 143 | 144 | public void IssueAuthenticationChallenge(object source, EventArgs e) 145 | { 146 | var context = ((HttpApplication)source).Context; 147 | 148 | if (allowLocal && context.Request.IsLocal) 149 | { 150 | return; 151 | } 152 | 153 | if (allowRedirects && IsRedirect(context.Response.StatusCode)) 154 | { 155 | return; 156 | } 157 | 158 | if (ShouldChallenge(context)) 159 | { 160 | // if authentication cookie is not set issue a basic challenge 161 | var authCookie = context.Request.Cookies.Get(AuthenticationCookieName); 162 | if (authCookie == null) 163 | { 164 | //make sure that user is not authencated yet 165 | if (!context.Response.Cookies.AllKeys.Contains(AuthenticationCookieName)) 166 | { 167 | context.Response.Clear(); 168 | context.Response.StatusCode = HttpNotAuthorizedStatusCode; 169 | context.Response.AddHeader(HttpWwwAuthenticateHeader, "Basic realm =\"" + Realm + "\""); 170 | } 171 | } 172 | } 173 | } 174 | 175 | /// 176 | /// Returns true if authentication challenge should be sent to client based on configured exclude rules 177 | /// 178 | private bool ShouldChallenge(HttpContext context) 179 | { 180 | // allow app setting take precedence 181 | if (!isEnabled) 182 | { 183 | return false; 184 | } 185 | 186 | // first check cache 187 | var key = string.Concat(context.Request.Path, context.Request.HttpMethod); 188 | if (shouldChallengeCache.ContainsKey(key)) 189 | { 190 | return shouldChallengeCache[key]; 191 | } 192 | 193 | // if value is not found in cache check exclude rules 194 | foreach (var urlVerbRegex in excludes) 195 | { 196 | if ((urlVerbRegex.Key.IsMatch(context.Request.Path) || urlVerbRegex.Key.IsMatch(context.Request.Url.Host)) && urlVerbRegex.Value.IsMatch(context.Request.HttpMethod)) 197 | { 198 | shouldChallengeCache[key] = false; 199 | 200 | return false; 201 | } 202 | } 203 | 204 | shouldChallengeCache[key] = true; 205 | return true; 206 | } 207 | 208 | private static bool IsRedirect(int httpStatusCode) 209 | { 210 | return httpStatusCode == (int)HttpStatusCode.MovedPermanently || 211 | httpStatusCode == (int)HttpStatusCode.Redirect || 212 | httpStatusCode == (int)HttpStatusCode.TemporaryRedirect; 213 | } 214 | 215 | protected virtual bool ValidateCredentials(string userName, string password) 216 | { 217 | var lowerCaseUserName = userName.ToLower(); 218 | 219 | if (activeUsers.ContainsKey(lowerCaseUserName) && activeUsers[lowerCaseUserName] == password) 220 | { 221 | return true; 222 | } 223 | 224 | return false; 225 | } 226 | 227 | protected virtual bool ExtractBasicCredentials(string authorizationHeader, ref string username, ref string password) 228 | { 229 | if (string.IsNullOrEmpty(authorizationHeader)) 230 | { 231 | return false; 232 | } 233 | 234 | string verifiedAuthorizationHeader = authorizationHeader.Trim(); 235 | if (verifiedAuthorizationHeader.IndexOf(HttpBasicSchemeName, StringComparison.InvariantCultureIgnoreCase) != 0) 236 | { 237 | return false; 238 | } 239 | 240 | // get the credential payload 241 | verifiedAuthorizationHeader = verifiedAuthorizationHeader.Substring(HttpBasicSchemeName.Length, verifiedAuthorizationHeader.Length - HttpBasicSchemeName.Length).Trim(); 242 | // decode the base 64 encoded credential payload 243 | byte[] credentialBase64DecodedArray = Convert.FromBase64String(verifiedAuthorizationHeader); 244 | string decodedAuthorizationHeader = Encoding.UTF8.GetString(credentialBase64DecodedArray, 0, credentialBase64DecodedArray.Length); 245 | 246 | // get the username, password, and realm 247 | int separatorPosition = decodedAuthorizationHeader.IndexOf(HttpCredentialSeparator); 248 | 249 | if (separatorPosition <= 0) 250 | { 251 | return false; 252 | } 253 | 254 | username = decodedAuthorizationHeader.Substring(0, separatorPosition).Trim(); 255 | password = decodedAuthorizationHeader.Substring(separatorPosition + 1, (decodedAuthorizationHeader.Length - separatorPosition - 1)).Trim(); 256 | 257 | if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) 258 | { 259 | return false; 260 | } 261 | 262 | return true; 263 | } 264 | 265 | public void Init(HttpApplication context) 266 | { 267 | var config = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~/web.config"); 268 | var basicAuth = TraverseConfigSections(config.RootSectionGroup); 269 | 270 | if (basicAuth == null) 271 | { 272 | System.Diagnostics.Debug.WriteLine("BasicAuthenticationModule not started - Configuration not found. Make sure that BasicAuthenticationConfigurationSection section is defined."); 273 | return; 274 | } 275 | 276 | allowRedirects = basicAuth.AllowRedirects; 277 | allowLocal = basicAuth.AllowLocal; 278 | 279 | var appSetting = ConfigurationManager.AppSettings[EnabledAppSetting]; 280 | if (appSetting != null) 281 | { 282 | isEnabled = appSetting == "true"; 283 | } 284 | 285 | InitCredentials(basicAuth); 286 | InitExcludes(basicAuth); 287 | 288 | // Subscribe to the authenticate event to perform the authentication. 289 | context.AuthenticateRequest += AuthenticateUser; 290 | 291 | // Subscribe to the EndRequest event to issue the authentication challenge if necessary. 292 | context.EndRequest += IssueAuthenticationChallenge; 293 | } 294 | 295 | private void InitCredentials(Configuration.BasicAuthenticationConfigurationSection basicAuth) 296 | { 297 | activeUsers = new Dictionary(); 298 | 299 | for (int i = 0; i < basicAuth.Credentials.Count; i++) 300 | { 301 | var credential = basicAuth.Credentials[i]; 302 | activeUsers.Add(credential.UserName.ToLower(), credential.Password); 303 | } 304 | } 305 | 306 | private void InitExcludes(Configuration.BasicAuthenticationConfigurationSection basicAuth) 307 | { 308 | var excludesAsString = new Dictionary(); 309 | excludes = new Dictionary(); 310 | var allowAnyRegex = AllowAnyRegex.ToString(); 311 | 312 | for (int i = 0; i < basicAuth.Excludes.Count; i++) 313 | { 314 | var excludeUrl = basicAuth.Excludes[i].Url; 315 | var excludeVerb = basicAuth.Excludes[i].Verb; 316 | 317 | if (string.IsNullOrEmpty(excludeUrl)) 318 | { 319 | excludeUrl = allowAnyRegex; 320 | } 321 | if (string.IsNullOrEmpty(excludeVerb)) 322 | { 323 | excludeVerb = allowAnyRegex; 324 | } 325 | 326 | excludesAsString[excludeUrl] = excludeVerb; 327 | } 328 | 329 | foreach (var url in excludesAsString.Keys) 330 | { 331 | var urlRegex = url == allowAnyRegex ? AllowAnyRegex : new Regex(url, RegexOptions.Compiled | RegexOptions.IgnoreCase); 332 | var verbRegex = excludesAsString[url] == allowAnyRegex ? AllowAnyRegex : new Regex(excludesAsString[url], RegexOptions.Compiled | RegexOptions.IgnoreCase); 333 | 334 | excludes[urlRegex] = verbRegex; 335 | } 336 | } 337 | 338 | private T TraverseConfigSections(ConfigurationSectionGroup group) where T : ConfigurationSection 339 | { 340 | foreach (ConfigurationSection section in group.Sections) 341 | { 342 | if (Type.GetType(section.SectionInformation.Type, false) == typeof(T)) 343 | return (T)section; 344 | } 345 | 346 | foreach (ConfigurationSectionGroup g in group.SectionGroups) 347 | { 348 | var section = TraverseConfigSections(g); 349 | if (section != null) 350 | { 351 | return section; 352 | } 353 | } 354 | 355 | return null; 356 | } 357 | 358 | public void Dispose() 359 | { 360 | // Do nothing here 361 | } 362 | } 363 | } -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication/Config/basicAuthentication.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication/Configuration/BasicAuthenticationConfigurationSection.cs: -------------------------------------------------------------------------------- 1 | using System.Configuration; 2 | 3 | namespace Devbridge.BasicAuthentication.Configuration 4 | { 5 | public class BasicAuthenticationConfigurationSection : ConfigurationSection 6 | { 7 | private const string CredentialsNode = "credentials"; 8 | private const string ExcludesNode = "excludes"; 9 | 10 | /// 11 | /// Gets or sets the credentials. 12 | /// 13 | /// 14 | /// The credentials. 15 | /// 16 | [ConfigurationProperty(CredentialsNode, IsRequired = false)] 17 | public CredentialElementCollection Credentials 18 | { 19 | get { return (CredentialElementCollection)this[CredentialsNode]; } 20 | set { this[CredentialsNode] = value; } 21 | } 22 | 23 | /// 24 | /// Gets or sets a value indicating whether authenticaiton module should allow redirects without issuing auth challenge. 25 | /// 26 | /// 27 | /// true to allow redirects; otherwise, false. 28 | /// 29 | [ConfigurationProperty("allowRedirects", DefaultValue = "false", IsRequired = false)] 30 | public bool AllowRedirects 31 | { 32 | get { return (bool)this["allowRedirects"]; } 33 | set { this["allowRedirects"] = value; } 34 | } 35 | 36 | /// 37 | /// Gets or sets a value indicating whether authenticaiton module should allow local requests without issuing auth challenge. 38 | /// 39 | /// 40 | /// true to allow redirects; otherwise, false. 41 | /// 42 | [ConfigurationProperty("allowLocal", DefaultValue = "false", IsRequired = false)] 43 | public bool AllowLocal 44 | { 45 | get { return (bool)this["allowLocal"]; } 46 | set { this["allowLocal"] = value; } 47 | } 48 | 49 | /// 50 | /// Gets or sets the URL exclusions. 51 | /// 52 | /// 53 | /// The URL exclusions. 54 | /// 55 | [ConfigurationProperty(ExcludesNode, IsRequired = false)] 56 | public ExcludeElementCollection Excludes 57 | { 58 | get { return (ExcludeElementCollection)this[ExcludesNode]; } 59 | set { this[ExcludesNode] = value; } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication/Configuration/CredentialElement.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Configuration; 3 | 4 | namespace Devbridge.BasicAuthentication.Configuration 5 | { 6 | public class CredentialElement : ConfigurationElement 7 | { 8 | private const string UserNameAttribute = "username"; 9 | private const string PasswordAttribute = "password"; 10 | 11 | /// 12 | /// Gets or sets the username. 13 | /// 14 | /// 15 | /// The user name. 16 | /// 17 | [ConfigurationProperty(UserNameAttribute, IsRequired = true)] 18 | public string UserName 19 | { 20 | get { return Convert.ToString(this[UserNameAttribute]); } 21 | set { this[UserNameAttribute] = value; } 22 | } 23 | 24 | /// 25 | /// Gets or sets the password. 26 | /// 27 | /// 28 | /// The password. 29 | /// 30 | [ConfigurationProperty(PasswordAttribute, IsRequired = true)] 31 | public string Password 32 | { 33 | get { return Convert.ToString(this[PasswordAttribute]); } 34 | set { this[PasswordAttribute] = value; } 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication/Configuration/CredentialElementCollection.cs: -------------------------------------------------------------------------------- 1 | using System.Configuration; 2 | 3 | namespace Devbridge.BasicAuthentication.Configuration 4 | { 5 | [ConfigurationCollection(typeof(CredentialElement), CollectionType = ConfigurationElementCollectionType.BasicMap)] 6 | public class CredentialElementCollection : ConfigurationElementCollection 7 | { 8 | public CredentialElement this[int index] 9 | { 10 | get 11 | { 12 | return (CredentialElement)BaseGet(index); 13 | } 14 | set 15 | { 16 | if (BaseGet(index) != null) 17 | { 18 | BaseRemoveAt(index); 19 | } 20 | BaseAdd(index, value); 21 | } 22 | } 23 | 24 | protected override ConfigurationElement CreateNewElement() 25 | { 26 | return new CredentialElement(); 27 | } 28 | 29 | protected override object GetElementKey(ConfigurationElement element) 30 | { 31 | return ((CredentialElement)element).UserName; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication/Configuration/ExcludeElement.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Configuration; 3 | 4 | namespace Devbridge.BasicAuthentication.Configuration 5 | { 6 | public class ExcludeElement : ConfigurationElement 7 | { 8 | private const string UrlAttribute = "url"; 9 | private const string VerbAttribute = "verb"; 10 | 11 | /// 12 | /// Gets or sets the url to exclude. 13 | /// 14 | /// 15 | /// The url. 16 | /// 17 | [ConfigurationProperty(UrlAttribute, IsRequired = false, IsKey = false)] 18 | public string Url 19 | { 20 | get { return Convert.ToString(this[UrlAttribute]); } 21 | set { this[UrlAttribute] = value; } 22 | } 23 | 24 | /// 25 | /// Gets or sets the verb to exclude. 26 | /// 27 | /// 28 | /// The verb. 29 | /// 30 | [ConfigurationProperty(VerbAttribute, IsRequired = false, IsKey = false)] 31 | public string Verb 32 | { 33 | get { return Convert.ToString(this[VerbAttribute]); } 34 | set { this[VerbAttribute] = value; } 35 | } 36 | 37 | public override string ToString() 38 | { 39 | return string.Concat(Url, '_', Verb); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication/Configuration/ExcludeElementCollection.cs: -------------------------------------------------------------------------------- 1 | using System.Configuration; 2 | 3 | namespace Devbridge.BasicAuthentication.Configuration 4 | { 5 | [ConfigurationCollection(typeof(ExcludeElement), CollectionType = ConfigurationElementCollectionType.BasicMap)] 6 | public class ExcludeElementCollection : ConfigurationElementCollection 7 | { 8 | public ExcludeElement this[int index] 9 | { 10 | get 11 | { 12 | return (ExcludeElement)BaseGet(index); 13 | } 14 | set 15 | { 16 | if (BaseGet(index) != null) 17 | { 18 | BaseRemoveAt(index); 19 | } 20 | BaseAdd(index, value); 21 | } 22 | } 23 | 24 | protected override ConfigurationElement CreateNewElement() 25 | { 26 | return new ExcludeElement(); 27 | } 28 | 29 | protected override object GetElementKey(ConfigurationElement element) 30 | { 31 | return ((ExcludeElement)element).ToString(); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication/Devbridge.BasicAuthentication.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {8B8D3FF3-9E4B-48D9-8BEF-52AB2651638A} 8 | Library 9 | Properties 10 | Devbridge.BasicAuthentication 11 | Devbridge.BasicAuthentication 12 | v4.0 13 | 512 14 | 15 | ..\ 16 | true 17 | 18 | 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | Properties\SharedAssemblyInfo.cs 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 69 | 70 | 71 | 72 | 79 | -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication/Devbridge.BasicAuthentication.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Devbridge.BasicAuthentication 5 | 1.0.0 6 | Devbridge Group 7 | Devbridge Group 8 | false 9 | 10 | This library contains basic authentification module, which can be mainly used for Azure websites. Not intended for production use. 11 | 12 | https://github.com/devbridge/AzurePowerTools 13 | Copyright 2017 14 | iis, basic authetification, azure 15 | en-US 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("DevBridge.BasicAuthentication")] 8 | [assembly: AssemblyDescription("")] 9 | 10 | // Setting ComVisible to false makes the types in this assembly not visible 11 | // to COM components. If you need to access a type in this assembly from 12 | // COM, set the ComVisible attribute to true on that type. 13 | [assembly: ComVisible(false)] 14 | 15 | // The following GUID is for the ID of the typelib if this project is exposed to COM 16 | [assembly: Guid("45346c62-265b-4c3d-9113-54e8f62a4904")] 17 | -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication/web.config.install.xdt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Devbridge.BasicAuthentication/web.config.uninstall.xdt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /PowerShell/PublishCloudService.ps1: -------------------------------------------------------------------------------- 1 | Param( $serviceName = "", 2 | $storageAccountName = "", 3 | $packageLocation = "", 4 | $cloudConfigLocation = "", 5 | $environment = "Production", 6 | $deploymentLabel = "Development", 7 | $timeStampFormat = "g", 8 | $alwaysDeleteExistingDeployments = 1, 9 | $enableDeploymentUpgrade = 1, 10 | $selectedsubscription = "", 11 | $subscriptionDataFile = "cloud.publishsettings" 12 | ) 13 | 14 | function Publish() 15 | { 16 | $deployment = Get-AzureDeployment -ServiceName $serviceName -Slot $slot -ErrorVariable a -ErrorAction silentlycontinue 17 | if ($a[0] -ne $null) 18 | { 19 | Write-Output "$(Get-Date –f $timeStampFormat) - No deployment is detected. Creating a new deployment. " 20 | } 21 | #check for existing deployment and then either upgrade, delete + deploy, or cancel according to $alwaysDeleteExistingDeployments and $enableDeploymentUpgrade boolean variables 22 | if ($deployment.Name -ne $null) 23 | { 24 | switch ($alwaysDeleteExistingDeployments) 25 | { 26 | 1 27 | { 28 | switch ($enableDeploymentUpgrade) 29 | { 30 | 1 #Update deployment inplace (usually faster, cheaper, won't destroy VIP) 31 | { 32 | Write-Output "$(Get-Date –f $timeStampFormat) - Deployment exists in $servicename. Upgrading deployment." 33 | UpgradeDeployment 34 | } 35 | 0 #Delete then create new deployment 36 | { 37 | Write-Output "$(Get-Date –f $timeStampFormat) - Deployment exists in $servicename. Deleting deployment." 38 | DeleteDeployment 39 | CreateNewDeployment 40 | 41 | } 42 | } # switch ($enableDeploymentUpgrade) 43 | } 44 | 0 45 | { 46 | Write-Output "$(Get-Date –f $timeStampFormat) - ERROR: Deployment exists in $servicename. Script execution cancelled." 47 | exit 48 | } 49 | } #switch ($alwaysDeleteExistingDeployments) 50 | } else { 51 | CreateNewDeployment 52 | } 53 | } 54 | 55 | function CreateNewDeployment() 56 | { 57 | write-progress -id 3 -activity "Creating New Deployment" -Status "In progress" 58 | Write-Output "$(Get-Date –f $timeStampFormat) - Creating New Deployment: In progress" 59 | 60 | $opstat = New-AzureDeployment -Slot $slot -Package $packageLocation -Configuration $cloudConfigLocation -label $deploymentLabel -ServiceName $serviceName 61 | 62 | $completeDeployment = Get-AzureDeployment -ServiceName $serviceName -Slot $slot -Verbose 63 | $completeDeploymentID = $completeDeployment.deploymentid 64 | 65 | write-progress -id 3 -activity "Creating New Deployment" -completed -Status "Complete" 66 | Write-Output "$(Get-Date –f $timeStampFormat) - Creating New Deployment: Complete, Deployment ID: $completeDeploymentID" 67 | 68 | StartInstances 69 | } 70 | 71 | function UpgradeDeployment() 72 | { 73 | write-progress -id 3 -activity "Upgrading Deployment" -Status "In progress" 74 | Write-Output "$(Get-Date –f $timeStampFormat) - Upgrading Deployment: In progress" 75 | 76 | # perform Update-Deployment 77 | $setdeployment = Set-AzureDeployment -Upgrade -Slot $slot -Package $packageLocation -Configuration $cloudConfigLocation -label $deploymentLabel -ServiceName $serviceName -Force 78 | 79 | $completeDeployment = Get-AzureDeployment -ServiceName $serviceName -Slot $slot 80 | $completeDeploymentID = $completeDeployment.deploymentid 81 | 82 | write-progress -id 3 -activity "Upgrading Deployment" -completed -Status "Complete" 83 | Write-Output "$(Get-Date –f $timeStampFormat) - Upgrading Deployment: Complete, Deployment ID: $completeDeploymentID" 84 | } 85 | 86 | function DeleteDeployment() 87 | { 88 | write-progress -id 2 -activity "Deleting Deployment" -Status "In progress" 89 | Write-Output "$(Get-Date –f $timeStampFormat) - Deleting Deployment: In progress" 90 | 91 | #WARNING - always deletes with force 92 | $removeDeployment = Remove-AzureDeployment -Slot $slot -ServiceName $serviceName -Force 93 | 94 | write-progress -id 2 -activity "Deleting Deployment: Complete" -completed -Status $removeDeployment 95 | Write-Output "$(Get-Date –f $timeStampFormat) - Deleting Deployment: Complete" 96 | } 97 | 98 | function StartInstances() 99 | { 100 | write-progress -id 4 -activity "Starting Instances" -status "In progress" 101 | Write-Output "$(Get-Date –f $timeStampFormat) - Starting Instances: In progress" 102 | 103 | $deployment = Get-AzureDeployment -ServiceName $serviceName -Slot $slot 104 | $runstatus = $deployment.Status 105 | 106 | if ($runstatus -ne 'Running') 107 | { 108 | $run = Set-AzureDeployment -Slot $slot -ServiceName $serviceName -Status Running 109 | } 110 | $deployment = Get-AzureDeployment -ServiceName $serviceName -Slot $slot 111 | $oldStatusStr = @("") * $deployment.RoleInstanceList.Count 112 | 113 | while (-not(AllInstancesRunning($deployment.RoleInstanceList))) 114 | { 115 | $i = 1 116 | foreach ($roleInstance in $deployment.RoleInstanceList) 117 | { 118 | $instanceName = $roleInstance.InstanceName 119 | $instanceStatus = $roleInstance.InstanceStatus 120 | 121 | if ($oldStatusStr[$i - 1] -ne $roleInstance.InstanceStatus) 122 | { 123 | $oldStatusStr[$i - 1] = $roleInstance.InstanceStatus 124 | Write-Output "$(Get-Date –f $timeStampFormat) - Starting Instance '$instanceName': $instanceStatus" 125 | } 126 | 127 | write-progress -id (4 + $i) -activity "Starting Instance '$instanceName'" -status "$instanceStatus" 128 | $i = $i + 1 129 | } 130 | 131 | sleep -Seconds 1 132 | 133 | $deployment = Get-AzureDeployment -ServiceName $serviceName -Slot $slot 134 | } 135 | 136 | $i = 1 137 | foreach ($roleInstance in $deployment.RoleInstanceList) 138 | { 139 | $instanceName = $roleInstance.InstanceName 140 | $instanceStatus = $roleInstance.InstanceStatus 141 | 142 | if ($oldStatusStr[$i - 1] -ne $roleInstance.InstanceStatus) 143 | { 144 | $oldStatusStr[$i - 1] = $roleInstance.InstanceStatus 145 | Write-Output "$(Get-Date –f $timeStampFormat) - Starting Instance '$instanceName': $instanceStatus" 146 | } 147 | 148 | $i = $i + 1 149 | } 150 | 151 | $deployment = Get-AzureDeployment -ServiceName $serviceName -Slot $slot 152 | $opstat = $deployment.Status 153 | 154 | write-progress -id 4 -activity "Starting Instances" -completed -status $opstat 155 | Write-Output "$(Get-Date –f $timeStampFormat) - Starting Instances: $opstat" 156 | } 157 | 158 | function AllInstancesRunning($roleInstanceList) 159 | { 160 | foreach ($roleInstance in $roleInstanceList) 161 | { 162 | if ($roleInstance.InstanceStatus -ne "ReadyRole") 163 | { 164 | return $false 165 | } 166 | } 167 | 168 | return $true 169 | } 170 | 171 | # specify path for Azure module (anyone knows how to configure PSModuleuPath?) 172 | $env:PSModulePath=$env:PSModulePath+";"+"C:\Program Files (x86)\Microsoft SDKs\Windows Azure\PowerShell" 173 | 174 | # append timestamp to deployment label: 175 | $deploymentLabel=$deploymentLabel + " " + (Get-Date -f g) 176 | 177 | # it should list Azure in available modules list: 178 | Get-Module -ListAvailable 179 | 180 | #configure powershell with Azure 1.7 modules 181 | Import-Module Azure 182 | 183 | # configure powershell with publishsettings for your subscription 184 | $pubsettings = $subscriptionDataFile 185 | Import-AzurePublishSettingsFile $pubsettings 186 | Select-AzureSubscription -SubscriptionName $selectedsubscription 187 | Set-AzureSubscription -CurrentStorageAccount $storageAccountName -SubscriptionName $selectedsubscription 188 | 189 | # set remaining environment variables for Azure cmdlets 190 | $subscription = Get-AzureSubscription $selectedsubscription 191 | $subscriptionname = $subscription.subscriptionname 192 | $subscriptionid = $subscription.subscriptionid 193 | $slot = $environment 194 | 195 | # main driver - publish & write progress to activity log 196 | Write-Output "$(Get-Date –f $timeStampFormat) - Azure Cloud Service deploy script started." 197 | Write-Output "$(Get-Date –f $timeStampFormat) - Preparing deployment of $deploymentLabel for $subscriptionname with Subscription ID $subscriptionid." 198 | 199 | Publish 200 | 201 | $deployment = Get-AzureDeployment -slot $slot -serviceName $servicename 202 | $deploymentUrl = $deployment.Url 203 | 204 | Write-Output "$(Get-Date –f $timeStampFormat) - Azure Cloud Service deploy script finished." 205 | Write-Output "$(Get-Date –f $timeStampFormat) - Created Cloud Service with URL: " 206 | Write-Output "$deploymentUrl" 207 | exit 0 208 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | DevBridge Azure Power Tools (http://www.devbridge.com) 2 | ======================================================================= 3 | Our Azure Power Tools project is the collection of Windows Azure related tools and extensions. Here at DevBridge, we believe in open communication and like to share our knowledge with others who may find it helpful. 4 | 5 | You can also take a look at our [Standard Web Project Template](https://github.com/devbridge/StandardWebProjectTemplate). 6 | 7 | ## Basic authentication for Windows Azure websites 8 | Basic authentication for Windows Azure websites is a HTTP managed module that provides basic authentication for web applications hosted in Windows Azure websites. For more information please read this [blog post](http://www.devbridge.com/articles/basic-authentication-for-windows-azure-websites). 9 | 10 | Basic authentication module has relation to two projects: 11 | - Devbridge.BasicAuthentication project has the implementation for the basic authentication module. 12 | - Devbridge.BasicAuthentication.Test is simple test website that can be used to test basic authentication. 13 | 14 | ###Configuration Settings 15 | * `allowRedirects`: indicates whether redirects are allowed without authentication. 16 | * `excludes`: allows to configure rules to exclude certain parts of application from authentication. 17 | 18 | ####Sample excludes 19 | ``` 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | ``` 31 | -------------------------------------------------------------------------------- /SharedAssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | [assembly: AssemblyCompany("DevBridge Inc.")] 4 | [assembly: AssemblyProduct("DevBridge Azure Power Tools")] 5 | [assembly: AssemblyCopyright("Copyright © DevBridge Inc. 2012")] 6 | [assembly: AssemblyTrademark("")] 7 | [assembly: AssemblyCulture("")] 8 | 9 | // You can specify all the values or you can default the Build and Revision Numbers 10 | // by using the '*' as shown below: 11 | [assembly: AssemblyVersion("1.0.0.0")] 12 | [assembly: AssemblyFileVersion("1.0.0.0")] -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright 2014 Devbridge Group 2 | http://www.devbridge.com/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /packages/repositories.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | --------------------------------------------------------------------------------