├── .gitattributes ├── .gitignore ├── AuthBot ├── AuthBot.csproj ├── AuthBot.nuspec ├── AuthText.Designer.cs ├── AuthText.resx ├── ContextConstants.cs ├── ContextExtensions.cs ├── Controllers │ └── OAuthCallbackController.cs ├── Dialogs │ └── AzureAuthDialog.cs ├── Helpers │ └── AzureActiveDirectoryHelper.cs ├── Models │ ├── AuthResult.cs │ ├── AuthSettings.cs │ ├── CancellationWords.cs │ ├── MemoryTokenCacheADAL.cs │ └── MemoryTokenCacheMSAL.cs ├── Properties │ └── AssemblyInfo.cs ├── app.config └── packages.config ├── LICENSE ├── PrivacyPolicy.md ├── README.md ├── SPAdminBot.json ├── SharePointAdminBot.Infra ├── AiExceptionLogger.cs ├── Create.cs ├── Forms │ ├── AskForUrlQuery.cs │ └── CreateSiteCollectionQuery.cs ├── Properties │ └── AssemblyInfo.cs ├── SharePointAdminBot.Infra.csproj ├── SharePointInfo.cs ├── app.config └── packages.config ├── SharePointAdminBot.sln ├── SharePointAdminBot ├── AppInsightsInitializer.cs ├── App_Start │ └── WebApiConfig.cs ├── ApplicationInsights.config ├── Controllers │ └── MessagesController.cs ├── Dialogs │ ├── FormBuilder.cs │ ├── MasterDialog.cs │ └── RootLuisDialog.cs ├── Global.asax ├── Global.asax.cs ├── Helpers.cs ├── Properties │ └── AssemblyInfo.cs ├── Service References │ └── Application Insights │ │ └── ConnectedService.json ├── SharePointAdminBot.csproj ├── Web.Debug.config ├── Web.Release.config ├── Web.config ├── default.htm └── packages.config └── TermsOfUse.MD /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | bld/ 21 | [Bb]in/ 22 | [Oo]bj/ 23 | [Ll]og/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | *.VC.VC.opendb 85 | 86 | # Visual Studio profiler 87 | *.psess 88 | *.vsp 89 | *.vspx 90 | *.sap 91 | 92 | # TFS 2012 Local Workspace 93 | $tf/ 94 | 95 | # Guidance Automation Toolkit 96 | *.gpState 97 | 98 | # ReSharper is a .NET coding add-in 99 | _ReSharper*/ 100 | *.[Rr]e[Ss]harper 101 | *.DotSettings.user 102 | 103 | # JustCode is a .NET coding add-in 104 | .JustCode 105 | 106 | # TeamCity is a build add-in 107 | _TeamCity* 108 | 109 | # DotCover is a Code Coverage Tool 110 | *.dotCover 111 | 112 | # NCrunch 113 | _NCrunch_* 114 | .*crunch*.local.xml 115 | nCrunchTemp_* 116 | 117 | # MightyMoose 118 | *.mm.* 119 | AutoTest.Net/ 120 | 121 | # Web workbench (sass) 122 | .sass-cache/ 123 | 124 | # Installshield output folder 125 | [Ee]xpress/ 126 | 127 | # DocProject is a documentation generator add-in 128 | DocProject/buildhelp/ 129 | DocProject/Help/*.HxT 130 | DocProject/Help/*.HxC 131 | DocProject/Help/*.hhc 132 | DocProject/Help/*.hhk 133 | DocProject/Help/*.hhp 134 | DocProject/Help/Html2 135 | DocProject/Help/html 136 | 137 | # Click-Once directory 138 | publish/ 139 | 140 | # Publish Web Output 141 | *.[Pp]ublish.xml 142 | *.azurePubxml 143 | # TODO: Comment the next line if you want to checkin your web deploy settings 144 | # but database connection strings (with potential passwords) will be unencrypted 145 | *.pubxml 146 | *.publishproj 147 | 148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 149 | # checkin your Azure Web App publish settings, but sensitive information contained 150 | # in these scripts will be unencrypted 151 | PublishScripts/ 152 | 153 | # NuGet Packages 154 | *.nupkg 155 | # The packages folder can be ignored because of Package Restore 156 | **/packages/* 157 | # except build/, which is used as an MSBuild target. 158 | !**/packages/build/ 159 | # Uncomment if necessary however generally it will be regenerated when needed 160 | #!**/packages/repositories.config 161 | # NuGet v3's project.json files produces more ignoreable files 162 | *.nuget.props 163 | *.nuget.targets 164 | 165 | # Microsoft Azure Build Output 166 | csx/ 167 | *.build.csdef 168 | 169 | # Microsoft Azure Emulator 170 | ecf/ 171 | rcf/ 172 | 173 | # Windows Store app package directories and files 174 | AppPackages/ 175 | BundleArtifacts/ 176 | Package.StoreAssociation.xml 177 | _pkginfo.txt 178 | 179 | # Visual Studio cache files 180 | # files ending in .cache can be ignored 181 | *.[Cc]ache 182 | # but keep track of directories ending in .cache 183 | !*.[Cc]ache/ 184 | 185 | # Others 186 | ClientBin/ 187 | ~$* 188 | *~ 189 | *.dbmdl 190 | *.dbproj.schemaview 191 | *.pfx 192 | *.publishsettings 193 | node_modules/ 194 | orleans.codegen.cs 195 | 196 | # Since there are multiple workflows, uncomment next line to ignore bower_components 197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 198 | #bower_components/ 199 | 200 | # RIA/Silverlight projects 201 | Generated_Code/ 202 | 203 | # Backup & report files from converting an old project file 204 | # to a newer Visual Studio version. Backup files are not needed, 205 | # because we have git ;-) 206 | _UpgradeReport_Files/ 207 | Backup*/ 208 | UpgradeLog*.XML 209 | UpgradeLog*.htm 210 | 211 | # SQL Server files 212 | *.mdf 213 | *.ldf 214 | 215 | # Business Intelligence projects 216 | *.rdl.data 217 | *.bim.layout 218 | *.bim_*.settings 219 | 220 | # Microsoft Fakes 221 | FakesAssemblies/ 222 | 223 | # GhostDoc plugin setting file 224 | *.GhostDoc.xml 225 | 226 | # Node.js Tools for Visual Studio 227 | .ntvs_analysis.dat 228 | 229 | # Visual Studio 6 build log 230 | *.plg 231 | 232 | # Visual Studio 6 workspace options file 233 | *.opt 234 | 235 | # Visual Studio LightSwitch build output 236 | **/*.HTMLClient/GeneratedArtifacts 237 | **/*.DesktopClient/GeneratedArtifacts 238 | **/*.DesktopClient/ModelManifest.xml 239 | **/*.Server/GeneratedArtifacts 240 | **/*.Server/ModelManifest.xml 241 | _Pvt_Extensions 242 | 243 | # Paket dependency manager 244 | .paket/paket.exe 245 | paket-files/ 246 | 247 | # FAKE - F# Make 248 | .fake/ 249 | 250 | # JetBrains Rider 251 | .idea/ 252 | *.sln.iml 253 | -------------------------------------------------------------------------------- /AuthBot/AuthBot.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B8AD59D3-C36D-4E18-B504-06871001BC8D} 8 | Library 9 | Properties 10 | AuthBot 11 | AuthBot 12 | v4.6 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | ..\packages\Autofac.4.2.1\lib\net45\Autofac.dll 36 | True 37 | 38 | 39 | ..\packages\Chronic.Signed.0.3.2\lib\net40\Chronic.dll 40 | True 41 | 42 | 43 | ..\packages\Microsoft.Bot.Builder.3.5.3\lib\net46\Microsoft.Bot.Builder.dll 44 | True 45 | 46 | 47 | ..\packages\Microsoft.Bot.Builder.3.5.3\lib\net46\Microsoft.Bot.Builder.Autofac.dll 48 | True 49 | 50 | 51 | ..\packages\Microsoft.Bot.Builder.3.5.3\lib\net46\Microsoft.Bot.Connector.dll 52 | True 53 | 54 | 55 | ..\packages\Microsoft.Identity.Client.1.0.304142221-alpha\lib\net45\Microsoft.Identity.Client.dll 56 | True 57 | 58 | 59 | ..\packages\Microsoft.Identity.Client.1.0.304142221-alpha\lib\net45\Microsoft.Identity.Client.Platform.dll 60 | True 61 | 62 | 63 | ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.13.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll 64 | True 65 | 66 | 67 | ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.13.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll 68 | True 69 | 70 | 71 | ..\packages\Microsoft.IdentityModel.Logging.1.1.0\lib\net451\Microsoft.IdentityModel.Logging.dll 72 | True 73 | 74 | 75 | ..\packages\Microsoft.IdentityModel.Protocol.Extensions.1.0.3.308261200\lib\net45\Microsoft.IdentityModel.Protocol.Extensions.dll 76 | True 77 | 78 | 79 | ..\packages\Microsoft.IdentityModel.Tokens.5.1.0\lib\net451\Microsoft.IdentityModel.Tokens.dll 80 | True 81 | 82 | 83 | ..\packages\Microsoft.Rest.ClientRuntime.2.3.5\lib\net45\Microsoft.Rest.ClientRuntime.dll 84 | True 85 | 86 | 87 | ..\packages\Microsoft.Win32.Primitives.4.0.1\lib\net46\Microsoft.Win32.Primitives.dll 88 | True 89 | 90 | 91 | ..\packages\Microsoft.WindowsAzure.ConfigurationManager.3.2.3\lib\net40\Microsoft.WindowsAzure.Configuration.dll 92 | True 93 | 94 | 95 | ..\packages\Newtonsoft.Json.9.0.2-beta1\lib\net45\Newtonsoft.Json.dll 96 | True 97 | 98 | 99 | 100 | 101 | 102 | 103 | ..\packages\System.Diagnostics.DiagnosticSource.4.0.0\lib\net46\System.Diagnostics.DiagnosticSource.dll 104 | True 105 | 106 | 107 | ..\packages\System.IdentityModel.Tokens.Jwt.4.0.3.308261200\lib\net45\System.IdentityModel.Tokens.Jwt.dll 108 | True 109 | 110 | 111 | 112 | 113 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll 114 | True 115 | 116 | 117 | 118 | 119 | ..\packages\System.Runtime.Serialization.Primitives.4.1.1\lib\net46\System.Runtime.Serialization.Primitives.dll 120 | True 121 | 122 | 123 | ..\packages\System.Security.Cryptography.Algorithms.4.2.0\lib\net46\System.Security.Cryptography.Algorithms.dll 124 | True 125 | 126 | 127 | ..\packages\System.Security.Cryptography.Encoding.4.0.0\lib\net46\System.Security.Cryptography.Encoding.dll 128 | True 129 | 130 | 131 | ..\packages\System.Security.Cryptography.Primitives.4.0.0\lib\net46\System.Security.Cryptography.Primitives.dll 132 | True 133 | 134 | 135 | ..\packages\System.Security.Cryptography.X509Certificates.4.1.0\lib\net46\System.Security.Cryptography.X509Certificates.dll 136 | True 137 | 138 | 139 | 140 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll 141 | True 142 | 143 | 144 | ..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.3\lib\net45\System.Web.Http.WebHost.dll 145 | True 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | True 156 | True 157 | AuthText.resx 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | ResXFileCodeGenerator 178 | AuthText.Designer.cs 179 | 180 | 181 | 182 | 189 | -------------------------------------------------------------------------------- /AuthBot/AuthBot.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | AuthBot 5 | 3.6.0-alpha 6 | AuthBot 7 | Mat Velloso 8 | NA 9 | https://github.com/microsoftdx/AuthBot 10 | false 11 | Unofficial Azure Active Directory authentication library for bots built with Microsoft Bot Framework 12 | MIT License 13 | en-US 14 | bot framework authentication azure o365 office bots conversational microsoft 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 | -------------------------------------------------------------------------------- /AuthBot/AuthText.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 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 AuthBot { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class AuthText { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal AuthText() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AuthBot.AuthText", typeof(AuthText).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized string similar to QUIT,CANCEL,STOP,GO BACK,RESET,HELP. 65 | /// 66 | internal static string CancellationWords { 67 | get { 68 | return ResourceManager.GetString("CancellationWords", resourceCulture); 69 | } 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /AuthBot/AuthText.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 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 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | QUIT,CANCEL,STOP,GO BACK,RESET,HELP 122 | 123 | -------------------------------------------------------------------------------- /AuthBot/ContextConstants.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file. 2 | namespace AuthBot 3 | { 4 | public class ContextConstants 5 | { 6 | public const string PersistedCookieKey = "persistedCookie"; 7 | public const string AuthResultKey = "authResult"; 8 | public const string MagicNumberKey = "authMagicNumber"; 9 | public const string MagicNumberValidated = "authMagicNumberValidated"; 10 | } 11 | } 12 | 13 | //********************************************************* 14 | // 15 | //AuthBot, https://github.com/microsoftdx/AuthBot 16 | // 17 | //Copyright (c) Microsoft Corporation 18 | //All rights reserved. 19 | // 20 | // MIT License: 21 | // Permission is hereby granted, free of charge, to any person obtaining 22 | // a copy of this software and associated documentation files (the 23 | // ""Software""), to deal in the Software without restriction, including 24 | // without limitation the rights to use, copy, modify, merge, publish, 25 | // distribute, sublicense, and/or sell copies of the Software, and to 26 | // permit persons to whom the Software is furnished to do so, subject to 27 | // the following conditions: 28 | 29 | 30 | 31 | 32 | // The above copyright notice and this permission notice shall be 33 | // included in all copies or substantial portions of the Software. 34 | 35 | 36 | 37 | 38 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, 39 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 40 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 41 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 42 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 43 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 44 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 45 | // 46 | //********************************************************* 47 | -------------------------------------------------------------------------------- /AuthBot/ContextExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file. 2 | namespace AuthBot 3 | { 4 | using System; 5 | using System.Diagnostics; 6 | using System.Threading.Tasks; 7 | using Helpers; 8 | using Microsoft.Bot.Builder.Dialogs; 9 | using Models; 10 | 11 | public static class ContextExtensions 12 | { 13 | public static async Task GetAccessToken(this IBotContext context, string resourceId) 14 | { 15 | AuthResult authResult; 16 | if (context.UserData.TryGetValue(ContextConstants.AuthResultKey, out authResult)) 17 | { 18 | try 19 | { 20 | InMemoryTokenCacheADAL tokenCache = new InMemoryTokenCacheADAL(authResult.TokenCache); 21 | var result = await AzureActiveDirectoryHelper.GetToken(authResult.UserUniqueId, tokenCache, resourceId); 22 | authResult.AccessToken = result.AccessToken; 23 | authResult.ExpiresOnUtcTicks = result.ExpiresOnUtcTicks; 24 | authResult.TokenCache = tokenCache.Serialize(); 25 | context.StoreAuthResult(authResult); 26 | } 27 | catch (Exception ex) 28 | { 29 | Trace.TraceError("Failed to renew token: " + ex.Message); 30 | await context.PostAsync("Your credentials expired and could not be renewed automatically!"); 31 | await context.Logout(); 32 | return null; 33 | } 34 | return authResult.AccessToken; 35 | } 36 | return null; 37 | } 38 | public static async Task GetAccessToken(this IBotContext context, string[] scopes) 39 | { 40 | AuthResult authResult; 41 | string validated = null; 42 | if (context.UserData.TryGetValue(ContextConstants.AuthResultKey, out authResult) && 43 | context.UserData.TryGetValue(ContextConstants.MagicNumberValidated, out validated) && 44 | validated == "true") 45 | { 46 | 47 | try 48 | { 49 | if (string.Equals(AuthSettings.Mode, "v2", StringComparison.OrdinalIgnoreCase)) 50 | { 51 | InMemoryTokenCacheMSAL tokenCache = new InMemoryTokenCacheMSAL(authResult.TokenCache); 52 | var result = await AzureActiveDirectoryHelper.GetToken(authResult.UserUniqueId, tokenCache, scopes); 53 | authResult.AccessToken = result.AccessToken; 54 | authResult.ExpiresOnUtcTicks = result.ExpiresOnUtcTicks; 55 | authResult.TokenCache = tokenCache.Serialize(); 56 | context.StoreAuthResult(authResult); 57 | } 58 | else if (string.Equals(AuthSettings.Mode, "b2c", StringComparison.OrdinalIgnoreCase)) 59 | { 60 | throw new NotImplementedException(); 61 | } 62 | } 63 | catch (Exception ex) 64 | { 65 | Trace.TraceError("Failed to renew token: " + ex.Message); 66 | await context.PostAsync("Your credentials expired and could not be renewed automatically!"); 67 | await context.Logout(); 68 | return null; 69 | } 70 | return authResult.AccessToken; 71 | } 72 | 73 | return null; 74 | } 75 | 76 | public static void StoreAuthResult(this IBotContext context, AuthResult authResult) 77 | { 78 | context.UserData.SetValue(ContextConstants.AuthResultKey, authResult); 79 | } 80 | public static AuthResult GetAuthResult(this IBotContext context) 81 | { 82 | AuthResult result = null; 83 | context.UserData.TryGetValue(ContextConstants.AuthResultKey, out result); 84 | return result; 85 | } 86 | 87 | public static async Task Logout(this IBotContext context) 88 | { 89 | context.UserData.RemoveValue(ContextConstants.AuthResultKey); 90 | context.UserData.RemoveValue(ContextConstants.MagicNumberKey); 91 | context.UserData.RemoveValue(ContextConstants.MagicNumberValidated); 92 | string signoutURl = "https://login.microsoftonline.com/common/oauth2/logout?post_logout_redirect_uri=" + System.Net.WebUtility.UrlEncode(AuthSettings.RedirectUrl); 93 | await context.PostAsync($"In order to finish the sign out, please click at this [link]({signoutURl})."); 94 | } 95 | 96 | } 97 | } 98 | 99 | //********************************************************* 100 | // 101 | //AuthBot, https://github.com/microsoftdx/AuthBot 102 | // 103 | //Copyright (c) Microsoft Corporation 104 | //All rights reserved. 105 | // 106 | // MIT License: 107 | // Permission is hereby granted, free of charge, to any person obtaining 108 | // a copy of this software and associated documentation files (the 109 | // ""Software""), to deal in the Software without restriction, including 110 | // without limitation the rights to use, copy, modify, merge, publish, 111 | // distribute, sublicense, and/or sell copies of the Software, and to 112 | // permit persons to whom the Software is furnished to do so, subject to 113 | // the following conditions: 114 | 115 | 116 | 117 | 118 | // The above copyright notice and this permission notice shall be 119 | // included in all copies or substantial portions of the Software. 120 | 121 | 122 | 123 | 124 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, 125 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 126 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 127 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 128 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 129 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 130 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 131 | // 132 | //********************************************************* 133 | -------------------------------------------------------------------------------- /AuthBot/Controllers/OAuthCallbackController.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file. 2 | namespace AuthBot.Controllers 3 | { 4 | using System; 5 | using System.Net; 6 | using System.Net.Http; 7 | using System.Security.Cryptography; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | using System.Web.Http; 11 | using Autofac; 12 | using Helpers; 13 | using Microsoft.Bot.Builder.Dialogs; 14 | using Microsoft.Bot.Builder.Dialogs.Internals; 15 | using Microsoft.Bot.Connector; 16 | using Microsoft.Rest; 17 | using Models; 18 | 19 | public class OAuthCallbackController : ApiController 20 | { 21 | private static RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider(); 22 | private static readonly uint MaxWriteAttempts = 5; 23 | 24 | [HttpGet] 25 | [Route("api/OAuthCallback")] 26 | public async Task OAuthCallback() 27 | { 28 | try 29 | { 30 | 31 | var resp = new HttpResponseMessage(HttpStatusCode.OK); 32 | resp.Content = new StringContent($"You have been signed out. You can now close this window.", System.Text.Encoding.UTF8, @"text/html"); 33 | return resp; 34 | 35 | } 36 | catch (Exception ex) 37 | { 38 | // Callback is called with no pending message as a result the login flow cannot be resumed. 39 | return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex); 40 | } 41 | 42 | } 43 | [HttpGet] 44 | [Route("api/OAuthCallback")] 45 | public async Task OAuthCallback( 46 | [FromUri] string code, 47 | [FromUri] string state, 48 | CancellationToken cancellationToken) 49 | { 50 | try 51 | { 52 | 53 | var queryParams = state; 54 | object tokenCache = null; 55 | if (string.Equals(AuthSettings.Mode, "v1", StringComparison.OrdinalIgnoreCase)) 56 | { 57 | tokenCache = new Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache(); 58 | } 59 | else if (string.Equals(AuthSettings.Mode, "v2", StringComparison.OrdinalIgnoreCase)) 60 | { 61 | tokenCache = new Microsoft.Identity.Client.TokenCache(); 62 | } 63 | else if (string.Equals(AuthSettings.Mode, "b2c", StringComparison.OrdinalIgnoreCase)) 64 | { 65 | } 66 | 67 | var resumptionCookie = UrlToken.Decode(queryParams); 68 | // Create the message that is send to conversation to resume the login flow 69 | var message = resumptionCookie.GetMessage(); 70 | 71 | using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message)) 72 | { 73 | var client = scope.Resolve(); 74 | AuthResult authResult = null; 75 | if (string.Equals(AuthSettings.Mode, "v1", StringComparison.OrdinalIgnoreCase)) 76 | { 77 | // Exchange the Auth code with Access token 78 | var token = await AzureActiveDirectoryHelper.GetTokenByAuthCodeAsync(code, (Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache)tokenCache); 79 | authResult = token; 80 | } 81 | else if (string.Equals(AuthSettings.Mode, "v2", StringComparison.OrdinalIgnoreCase)) 82 | { 83 | // Exchange the Auth code with Access token 84 | var token = await AzureActiveDirectoryHelper.GetTokenByAuthCodeAsync(code, (Microsoft.Identity.Client.TokenCache)tokenCache,Models.AuthSettings.Scopes); 85 | authResult = token; 86 | } 87 | else if (string.Equals(AuthSettings.Mode, "b2c", StringComparison.OrdinalIgnoreCase)) 88 | { 89 | } 90 | 91 | IStateClient sc = scope.Resolve(); 92 | 93 | //IMPORTANT: DO NOT REMOVE THE MAGIC NUMBER CHECK THAT WE DO HERE. THIS IS AN ABSOLUTE SECURITY REQUIREMENT 94 | //REMOVING THIS WILL REMOVE YOUR BOT AND YOUR USERS TO SECURITY VULNERABILITIES. 95 | //MAKE SURE YOU UNDERSTAND THE ATTACK VECTORS AND WHY THIS IS IN PLACE. 96 | int magicNumber = GenerateRandomNumber(); 97 | bool writeSuccessful = false; 98 | uint writeAttempts = 0; 99 | while (!writeSuccessful && writeAttempts++ < MaxWriteAttempts) 100 | { 101 | try 102 | { 103 | BotData userData = sc.BotState.GetUserData(message.ChannelId, message.From.Id); 104 | userData.SetProperty(ContextConstants.AuthResultKey, authResult); 105 | userData.SetProperty(ContextConstants.MagicNumberKey, magicNumber); 106 | userData.SetProperty(ContextConstants.MagicNumberValidated, "false"); 107 | sc.BotState.SetUserData(message.ChannelId, message.From.Id, userData); 108 | writeSuccessful = true; 109 | } 110 | catch (HttpOperationException) 111 | { 112 | writeSuccessful = false; 113 | } 114 | } 115 | var resp = new HttpResponseMessage(HttpStatusCode.OK); 116 | if (!writeSuccessful) 117 | { 118 | message.Text = String.Empty; // fail the login process if we can't write UserData 119 | await Conversation.ResumeAsync(resumptionCookie, message); 120 | resp.Content = new StringContent("Could not log you in at this time, please try again later", System.Text.Encoding.UTF8, @"text/html"); 121 | } 122 | else 123 | { 124 | await Conversation.ResumeAsync(resumptionCookie, message); 125 | resp.Content = new StringContent($"Almost done! Please copy this number and paste it back to your chat so your authentication can complete:

{magicNumber}

.", System.Text.Encoding.UTF8, @"text/html"); 126 | } 127 | return resp; 128 | } 129 | } 130 | catch (Exception ex) 131 | { 132 | // Callback is called with no pending message as a result the login flow cannot be resumed. 133 | return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ex); 134 | } 135 | } 136 | 137 | private int GenerateRandomNumber() 138 | { 139 | int number = 0; 140 | byte[] randomNumber = new byte[1]; 141 | do 142 | { 143 | rngCsp.GetBytes(randomNumber); 144 | var digit = randomNumber[0] % 10; 145 | number = number * 10 + digit; 146 | } while (number.ToString().Length < 6); 147 | return number; 148 | 149 | } 150 | 151 | } 152 | } 153 | 154 | 155 | //********************************************************* 156 | // 157 | //AuthBot, https://github.com/microsoftdx/AuthBot 158 | // 159 | //Copyright (c) Microsoft Corporation 160 | //All rights reserved. 161 | // 162 | // MIT License: 163 | // Permission is hereby granted, free of charge, to any person obtaining 164 | // a copy of this software and associated documentation files (the 165 | // ""Software""), to deal in the Software without restriction, including 166 | // without limitation the rights to use, copy, modify, merge, publish, 167 | // distribute, sublicense, and/or sell copies of the Software, and to 168 | // permit persons to whom the Software is furnished to do so, subject to 169 | // the following conditions: 170 | 171 | 172 | 173 | 174 | // The above copyright notice and this permission notice shall be 175 | // included in all copies or substantial portions of the Software. 176 | 177 | 178 | 179 | 180 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, 181 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 182 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 183 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 184 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 185 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 186 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 187 | // 188 | //********************************************************* 189 | -------------------------------------------------------------------------------- /AuthBot/Dialogs/AzureAuthDialog.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file. 2 | namespace AuthBot.Dialogs 3 | { 4 | using System; 5 | using System.Threading.Tasks; 6 | using Helpers; 7 | using Microsoft.Bot.Builder.Dialogs; 8 | using Microsoft.Bot.Connector; 9 | using Models; 10 | using Microsoft.Bot.Builder.Dialogs.Internals; 11 | using Autofac; 12 | using System.Collections.Generic; 13 | using System.Text.RegularExpressions; 14 | 15 | [Serializable] 16 | public class AzureAuthDialog : IDialog 17 | { 18 | protected string resourceId { get; } 19 | protected string[] scopes { get; } 20 | protected string prompt { get; } 21 | 22 | 23 | 24 | public AzureAuthDialog(string resourceId, string prompt = "Please click to sign in: ") 25 | { 26 | this.resourceId = resourceId; 27 | this.prompt = prompt; 28 | } 29 | public AzureAuthDialog(string[] scopes, string prompt = "Please click to sign in: ") 30 | { 31 | this.scopes = scopes; 32 | this.prompt = prompt; 33 | } 34 | 35 | 36 | public async Task StartAsync(IDialogContext context) 37 | { 38 | context.Wait(this.MessageReceivedAsync); 39 | } 40 | 41 | public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable argument) 42 | { 43 | var msg = await argument; 44 | 45 | AuthResult authResult; 46 | string validated = ""; 47 | int magicNumber = 0; 48 | if (context.UserData.TryGetValue(ContextConstants.AuthResultKey, out authResult)) 49 | { 50 | try 51 | { 52 | //IMPORTANT: DO NOT REMOVE THE MAGIC NUMBER CHECK THAT WE DO HERE. THIS IS AN ABSOLUTE SECURITY REQUIREMENT 53 | //REMOVING THIS WILL REMOVE YOUR BOT AND YOUR USERS TO SECURITY VULNERABILITIES. 54 | //MAKE SURE YOU UNDERSTAND THE ATTACK VECTORS AND WHY THIS IS IN PLACE. 55 | context.UserData.TryGetValue(ContextConstants.MagicNumberValidated, out validated); 56 | if (validated == "true") 57 | { 58 | context.Done($"Thanks {authResult.UserName}. You are now logged in. "); 59 | } 60 | else if (context.UserData.TryGetValue(ContextConstants.MagicNumberKey, out magicNumber)) 61 | { 62 | if (msg.Text == null) 63 | { 64 | await context.PostAsync($"Please paste back the number you received in your authentication screen."); 65 | 66 | context.Wait(this.MessageReceivedAsync); 67 | } 68 | else 69 | { 70 | 71 | if (msg.Text.Length >= 6 && magicNumber.ToString() == msg.Text.Substring(0, 6)) 72 | { 73 | context.UserData.SetValue(ContextConstants.MagicNumberValidated, "true"); 74 | context.Done($"Thanks {authResult.UserName}. You are now logged in. "); 75 | } 76 | else 77 | { 78 | context.UserData.RemoveValue(ContextConstants.AuthResultKey); 79 | context.UserData.SetValue(ContextConstants.MagicNumberValidated, "false"); 80 | context.UserData.RemoveValue(ContextConstants.MagicNumberKey); 81 | await context.PostAsync($"I'm sorry but I couldn't validate your number. Please try authenticating once again. "); 82 | 83 | context.Wait(this.MessageReceivedAsync); 84 | } 85 | } 86 | } 87 | } 88 | catch 89 | { 90 | context.UserData.RemoveValue(ContextConstants.AuthResultKey); 91 | context.UserData.SetValue(ContextConstants.MagicNumberValidated, "false"); 92 | context.UserData.RemoveValue(ContextConstants.MagicNumberKey); 93 | context.Done($"I'm sorry but something went wrong while authenticating."); 94 | } 95 | } 96 | else 97 | { 98 | await this.LogIn(context, msg); 99 | } 100 | } 101 | 102 | /// 103 | /// Prompts the user to login. This can be overridden inorder to allow custom prompt messages or cards per channel. 104 | /// 105 | /// Chat context 106 | /// Chat message 107 | /// OAuth URL for authenticating user 108 | /// Task from Posting or prompt to the context. 109 | protected virtual Task PromptToLogin(IDialogContext context, IMessageActivity msg, string authenticationUrl) 110 | { 111 | Attachment plAttachment = null; 112 | switch (msg.ChannelId) 113 | { 114 | case "emulator": 115 | { 116 | SigninCard plCard = new SigninCard(this.prompt, GetCardActions(authenticationUrl, "signin")); 117 | plAttachment = plCard.ToAttachment(); 118 | break; 119 | } 120 | case "skype": 121 | { 122 | SigninCard plCard = new SigninCard(this.prompt, GetCardActions(authenticationUrl, "signin")); 123 | plAttachment = plCard.ToAttachment(); 124 | break; 125 | } 126 | // Teams does not yet support signin cards 127 | case "msteams": 128 | { 129 | ThumbnailCard plCard = new ThumbnailCard() 130 | { 131 | Title = this.prompt, 132 | Subtitle = "", 133 | Images = new List(), 134 | Buttons = GetCardActions(authenticationUrl, "openUrl") 135 | }; 136 | plAttachment = plCard.ToAttachment(); 137 | break; 138 | } 139 | default: 140 | { 141 | SigninCard plCard = new SigninCard(this.prompt, GetCardActions(authenticationUrl, "signin")); 142 | plAttachment = plCard.ToAttachment(); 143 | break; 144 | } 145 | // return context.PostAsync(this.prompt + "[Click here](" + authenticationUrl + ")"); 146 | } 147 | 148 | IMessageActivity response = context.MakeMessage(); 149 | response.Recipient = msg.From; 150 | response.Type = "message"; 151 | 152 | response.Attachments = new List(); 153 | response.Attachments.Add(plAttachment); 154 | 155 | return context.PostAsync(response); 156 | } 157 | 158 | private List GetCardActions(string authenticationUrl, string actionType) 159 | { 160 | List cardButtons = new List(); 161 | CardAction plButton = new CardAction() 162 | { 163 | Value = authenticationUrl, 164 | Type = actionType, 165 | Title = "Authentication Required" 166 | }; 167 | cardButtons.Add(plButton); 168 | return cardButtons; 169 | } 170 | 171 | private async Task LogIn(IDialogContext context, IMessageActivity msg) 172 | { 173 | try 174 | { 175 | string token; 176 | if (resourceId != null) 177 | token = await context.GetAccessToken(resourceId); 178 | else 179 | token = await context.GetAccessToken(scopes); 180 | 181 | if (string.IsNullOrEmpty(token)) 182 | { 183 | if (msg.Text != null && 184 | CancellationWords.GetCancellationWords().Contains(msg.Text.ToUpper())) 185 | { 186 | context.Done(string.Empty); 187 | } 188 | else 189 | { 190 | var resumptionCookie = new ResumptionCookie(msg); 191 | 192 | string authenticationUrl; 193 | if (resourceId != null) 194 | authenticationUrl = await AzureActiveDirectoryHelper.GetAuthUrlAsync(resumptionCookie, resourceId); 195 | else 196 | authenticationUrl = await AzureActiveDirectoryHelper.GetAuthUrlAsync(resumptionCookie, scopes); 197 | 198 | await PromptToLogin(context, msg, authenticationUrl); 199 | context.Wait(this.MessageReceivedAsync); 200 | } 201 | } 202 | else 203 | { 204 | context.Done(string.Empty); 205 | } 206 | } 207 | catch (Exception ex) 208 | { 209 | throw ex; 210 | } 211 | } 212 | } 213 | } 214 | 215 | 216 | //********************************************************* 217 | // 218 | //AuthBot, https://github.com/microsoftdx/AuthBot 219 | // 220 | //Copyright (c) Microsoft Corporation 221 | //All rights reserved. 222 | // 223 | // MIT License: 224 | // Permission is hereby granted, free of charge, to any person obtaining 225 | // a copy of this software and associated documentation files (the 226 | // ""Software""), to deal in the Software without restriction, including 227 | // without limitation the rights to use, copy, modify, merge, publish, 228 | // distribute, sublicense, and/or sell copies of the Software, and to 229 | // permit persons to whom the Software is furnished to do so, subject to 230 | // the following conditions: 231 | 232 | 233 | 234 | 235 | // The above copyright notice and this permission notice shall be 236 | // included in all copies or substantial portions of the Software. 237 | 238 | 239 | 240 | 241 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, 242 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 243 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 244 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 245 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 246 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 247 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 248 | // 249 | //********************************************************* 250 | -------------------------------------------------------------------------------- /AuthBot/Helpers/AzureActiveDirectoryHelper.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file. 2 | namespace AuthBot.Helpers 3 | { 4 | using System; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | using System.Web; 8 | using Microsoft.Bot.Builder.Dialogs; 9 | using Models; 10 | 11 | public static class AzureActiveDirectoryHelper 12 | { 13 | public static async Task GetAuthUrlAsync(ResumptionCookie resumptionCookie, string resourceId) 14 | { 15 | var extraParameters = BuildExtraParameters(resumptionCookie); 16 | 17 | Uri redirectUri = new Uri(AuthSettings.RedirectUrl); 18 | Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext context = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(AuthSettings.EndpointUrl + "/" + AuthSettings.Tenant); 19 | var uri = await context.GetAuthorizationRequestUrlAsync( 20 | resourceId, 21 | AuthSettings.ClientId, 22 | redirectUri, 23 | Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier.AnyUser, 24 | $"state={extraParameters}"); 25 | return uri.ToString(); 26 | 27 | } 28 | 29 | public static async Task GetAuthUrlAsync(ResumptionCookie resumptionCookie, string[] scopes) 30 | { 31 | var extraParameters = BuildExtraParameters(resumptionCookie); 32 | Uri redirectUri = new Uri(AuthSettings.RedirectUrl); 33 | if (string.Equals(AuthSettings.Mode, "v2", StringComparison.OrdinalIgnoreCase)) 34 | { 35 | InMemoryTokenCacheMSAL tokenCache = new InMemoryTokenCacheMSAL(); 36 | Microsoft.Identity.Client.ConfidentialClientApplication client = new Microsoft.Identity.Client.ConfidentialClientApplication(AuthSettings.ClientId, redirectUri.ToString(), 37 | new Microsoft.Identity.Client.ClientCredential(AuthSettings.ClientSecret), 38 | tokenCache); 39 | 40 | //var uri = "https://login.microsoftonline.com/" + AuthSettings.Tenant + "/oauth2/v2.0/authorize?response_type=code" + 41 | // "&client_id=" + AuthSettings.ClientId + 42 | // "&client_secret=" + AuthSettings.ClientSecret + 43 | // "&redirect_uri=" + HttpUtility.UrlEncode(AuthSettings.RedirectUrl) + 44 | // "&scope=" + HttpUtility.UrlEncode("openid profile " + string.Join(" ", scopes)) + 45 | // "&state=" + encodedCookie; 46 | 47 | 48 | var uri = await client.GetAuthorizationRequestUrlAsync( 49 | scopes, 50 | null, 51 | $"state={extraParameters}"); 52 | return uri.ToString(); 53 | } 54 | else if (string.Equals(AuthSettings.Mode, "b2c", StringComparison.OrdinalIgnoreCase)) 55 | { 56 | return null; 57 | } 58 | return null; 59 | } 60 | 61 | public static async Task GetTokenByAuthCodeAsync(string authorizationCode, Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache tokenCache) 62 | { 63 | Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext context = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(AuthSettings.EndpointUrl + "/" + AuthSettings.Tenant, tokenCache); 64 | Uri redirectUri = new Uri(AuthSettings.RedirectUrl); 65 | var result = await context.AcquireTokenByAuthorizationCodeAsync(authorizationCode, redirectUri, new Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential(AuthSettings.ClientId, AuthSettings.ClientSecret)); 66 | AuthResult authResult = AuthResult.FromADALAuthenticationResult(result, tokenCache); 67 | return authResult; 68 | } 69 | public static async Task GetTokenByAuthCodeAsync(string authorizationCode, Microsoft.Identity.Client.TokenCache tokenCache, string[] scopes) 70 | { 71 | Microsoft.Identity.Client.ConfidentialClientApplication client = new Microsoft.Identity.Client.ConfidentialClientApplication(AuthSettings.ClientId, AuthSettings.RedirectUrl, new Microsoft.Identity.Client.ClientCredential(AuthSettings.ClientSecret), tokenCache); 72 | Uri redirectUri = new Uri(AuthSettings.RedirectUrl); 73 | var result = await client.AcquireTokenByAuthorizationCodeAsync(scopes, authorizationCode); 74 | AuthResult authResult = AuthResult.FromMSALAuthenticationResult(result, tokenCache); 75 | return authResult; 76 | } 77 | 78 | public static async Task GetToken(string userUniqueId, Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache tokenCache, string resourceId) 79 | { 80 | Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext context = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(AuthSettings.EndpointUrl + "/" + AuthSettings.Tenant, tokenCache); 81 | var result = await context.AcquireTokenSilentAsync(resourceId, new Microsoft.IdentityModel.Clients.ActiveDirectory.ClientCredential(AuthSettings.ClientId, AuthSettings.ClientSecret), new Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifier(userUniqueId, Microsoft.IdentityModel.Clients.ActiveDirectory.UserIdentifierType.UniqueId)); 82 | AuthResult authResult = AuthResult.FromADALAuthenticationResult(result, tokenCache); 83 | return authResult; 84 | } 85 | 86 | public static async Task GetToken(string userUniqueId, Microsoft.Identity.Client.TokenCache tokenCache, string[] scopes) 87 | { 88 | Microsoft.Identity.Client.ConfidentialClientApplication client = new Microsoft.Identity.Client.ConfidentialClientApplication(AuthSettings.ClientId, AuthSettings.RedirectUrl, new Microsoft.Identity.Client.ClientCredential(AuthSettings.ClientSecret), tokenCache); 89 | var result = await client.AcquireTokenSilentAsync(scopes, userUniqueId); 90 | AuthResult authResult = AuthResult.FromMSALAuthenticationResult(result, tokenCache); 91 | return authResult; 92 | } 93 | 94 | public static string TokenEncoder(string token) 95 | { 96 | return HttpServerUtility.UrlTokenEncode(Encoding.UTF8.GetBytes(token)); 97 | } 98 | 99 | public static string TokenDecoder(string token) 100 | { 101 | return Encoding.UTF8.GetString(HttpServerUtility.UrlTokenDecode(token)); 102 | } 103 | 104 | private static string BuildExtraParameters(ResumptionCookie resumptionCookie) 105 | { 106 | var encodedCookie = UrlToken.Encode(resumptionCookie); 107 | 108 | //var queryString = HttpUtility.ParseQueryString(string.Empty); 109 | //queryString["userId"] = resumptionCookie.Address.UserId; 110 | //queryString["botId"] = resumptionCookie.Address.BotId; 111 | //queryString["conversationId"] = resumptionCookie.Address.ConversationId; 112 | //queryString["serviceUrl"] = resumptionCookie.Address.ServiceUrl; 113 | //queryString["channelId"] = resumptionCookie.Address.ChannelId; 114 | //queryString["locale"] = resumptionCookie.Locale ?? "en"; 115 | 116 | //return TokenEncoder(queryString.ToString()); 117 | return encodedCookie; 118 | } 119 | } 120 | } 121 | 122 | //********************************************************* 123 | // 124 | //AuthBot, https://github.com/microsoftdx/AuthBot 125 | // 126 | //Copyright (c) Microsoft Corporation 127 | //All rights reserved. 128 | // 129 | // MIT License: 130 | // Permission is hereby granted, free of charge, to any person obtaining 131 | // a copy of this software and associated documentation files (the 132 | // ""Software""), to deal in the Software without restriction, including 133 | // without limitation the rights to use, copy, modify, merge, publish, 134 | // distribute, sublicense, and/or sell copies of the Software, and to 135 | // permit persons to whom the Software is furnished to do so, subject to 136 | // the following conditions: 137 | 138 | 139 | 140 | 141 | // The above copyright notice and this permission notice shall be 142 | // included in all copies or substantial portions of the Software. 143 | 144 | 145 | 146 | 147 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, 148 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 149 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 150 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 151 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 152 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 153 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 154 | // 155 | //********************************************************* 156 | -------------------------------------------------------------------------------- /AuthBot/Models/AuthResult.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file. 2 | namespace AuthBot.Models 3 | { 4 | using System; 5 | 6 | [Serializable] 7 | public class AuthResult 8 | { 9 | public string AccessToken { get; set; } 10 | public string UserName { get; set; } 11 | public string UserUniqueId { get; set; } 12 | public long ExpiresOnUtcTicks { get; set; } 13 | public byte[] TokenCache { get; set; } 14 | public string TenantId { get; set; } 15 | public string Upn { get; set; } 16 | 17 | public static AuthResult FromADALAuthenticationResult(Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationResult authResult, Microsoft.IdentityModel.Clients.ActiveDirectory.TokenCache tokenCache) 18 | { 19 | var result = new AuthResult 20 | { 21 | AccessToken = authResult.AccessToken, 22 | UserName = $"{authResult.UserInfo.GivenName} {authResult.UserInfo.FamilyName}", 23 | UserUniqueId = authResult.UserInfo.UniqueId, 24 | ExpiresOnUtcTicks = authResult.ExpiresOn.UtcTicks, 25 | TokenCache = tokenCache.Serialize(), 26 | TenantId = authResult.TenantId, 27 | Upn = authResult.UserInfo.DisplayableId 28 | }; 29 | 30 | return result; 31 | } 32 | 33 | public static AuthResult FromMSALAuthenticationResult(Microsoft.Identity.Client.AuthenticationResult authResult, Microsoft.Identity.Client.TokenCache tokenCache) 34 | { 35 | var result = new AuthResult 36 | { 37 | AccessToken = authResult.Token, 38 | UserName = $"{authResult.User.Name}", 39 | UserUniqueId = authResult.User.UniqueId, 40 | ExpiresOnUtcTicks = authResult.ExpiresOn.UtcTicks, 41 | TokenCache = tokenCache.Serialize(), 42 | TenantId = authResult.TenantId 43 | }; 44 | 45 | return result; 46 | } 47 | } 48 | } 49 | //********************************************************* 50 | // 51 | //AuthBot, https://github.com/microsoftdx/AuthBot 52 | // 53 | //Copyright (c) Microsoft Corporation 54 | //All rights reserved. 55 | // 56 | // MIT License: 57 | // Permission is hereby granted, free of charge, to any person obtaining 58 | // a copy of this software and associated documentation files (the 59 | // ""Software""), to deal in the Software without restriction, including 60 | // without limitation the rights to use, copy, modify, merge, publish, 61 | // distribute, sublicense, and/or sell copies of the Software, and to 62 | // permit persons to whom the Software is furnished to do so, subject to 63 | // the following conditions: 64 | 65 | 66 | 67 | 68 | // The above copyright notice and this permission notice shall be 69 | // included in all copies or substantial portions of the Software. 70 | 71 | 72 | 73 | 74 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, 75 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 76 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 77 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 78 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 79 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 80 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 81 | // 82 | //********************************************************* 83 | -------------------------------------------------------------------------------- /AuthBot/Models/AuthSettings.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file. 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace AuthBot.Models 9 | { 10 | public class AuthSettings 11 | { 12 | public static string ClientId { get; set; } 13 | public static string ClientSecret { get; set; } 14 | public static string EndpointUrl { get; set; } 15 | public static string Tenant { get; set; } 16 | public static string RedirectUrl { get; set; } 17 | public static string Mode { get; set; } 18 | public static string[] Scopes { get; set; } 19 | 20 | 21 | } 22 | } 23 | 24 | //********************************************************* 25 | // 26 | //AuthBot, https://github.com/microsoftdx/AuthBot 27 | // 28 | //Copyright (c) Microsoft Corporation 29 | //All rights reserved. 30 | // 31 | // MIT License: 32 | // Permission is hereby granted, free of charge, to any person obtaining 33 | // a copy of this software and associated documentation files (the 34 | // ""Software""), to deal in the Software without restriction, including 35 | // without limitation the rights to use, copy, modify, merge, publish, 36 | // distribute, sublicense, and/or sell copies of the Software, and to 37 | // permit persons to whom the Software is furnished to do so, subject to 38 | // the following conditions: 39 | 40 | 41 | 42 | 43 | // The above copyright notice and this permission notice shall be 44 | // included in all copies or substantial portions of the Software. 45 | 46 | 47 | 48 | 49 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, 50 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 51 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 52 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 53 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 54 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 55 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 56 | // 57 | //********************************************************* 58 | -------------------------------------------------------------------------------- /AuthBot/Models/CancellationWords.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace AuthBot.Models 8 | { 9 | public class CancellationWords 10 | { 11 | public static List GetCancellationWords() 12 | { 13 | return AuthText.CancellationWords.Split(',').ToList(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /AuthBot/Models/MemoryTokenCacheADAL.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file. 2 | using Microsoft.IdentityModel.Clients.ActiveDirectory; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading; 7 | using System.Web; 8 | 9 | namespace AuthBot.Models 10 | { 11 | public class InMemoryTokenCacheADAL : TokenCache 12 | { 13 | string CacheId = string.Empty; 14 | private Dictionary cache = new Dictionary(); 15 | 16 | public InMemoryTokenCacheADAL() 17 | { 18 | CacheId = "_TokenCache"; 19 | this.AfterAccess = AfterAccessNotification; 20 | this.BeforeAccess = BeforeAccessNotification; 21 | Load(); 22 | } 23 | 24 | public InMemoryTokenCacheADAL(byte[] tokenCache) 25 | { 26 | CacheId = "_TokenCache"; 27 | this.AfterAccess = AfterAccessNotification; 28 | this.BeforeAccess = BeforeAccessNotification; 29 | this.Deserialize(tokenCache); 30 | } 31 | 32 | public void SaveUserStateValue(string state) 33 | { 34 | cache[CacheId + "_state"] = state; 35 | } 36 | public string ReadUserStateValue() 37 | { 38 | string state = string.Empty; 39 | state=(string)cache[CacheId + "_state"]; 40 | return state; 41 | } 42 | public void Load() 43 | { 44 | if (cache.ContainsKey(CacheId)) 45 | this.Deserialize((byte[])cache[CacheId]); 46 | } 47 | 48 | public void Persist() 49 | { 50 | // Optimistically set HasStateChanged to false. We need to do it early to avoid losing changes made by a concurrent thread. 51 | this.HasStateChanged = false; 52 | // Reflect changes in the persistent store 53 | cache[CacheId] = this.Serialize(); 54 | } 55 | 56 | // Empties the persistent store. 57 | public override void Clear() 58 | { 59 | base.Clear(); 60 | cache.Clear(); 61 | } 62 | 63 | // Triggered right before ADAL needs to access the cache. 64 | // Reload the cache from the persistent store in case it changed since the last access. 65 | void BeforeAccessNotification(TokenCacheNotificationArgs args) 66 | { 67 | Load(); 68 | } 69 | 70 | // Triggered right after ADAL accessed the cache. 71 | void AfterAccessNotification(TokenCacheNotificationArgs args) 72 | { 73 | // if the access operation resulted in a cache update 74 | if (this.HasStateChanged) 75 | { 76 | Persist(); 77 | } 78 | } 79 | } 80 | 81 | } 82 | 83 | //********************************************************* 84 | // 85 | //AuthBot, https://github.com/microsoftdx/AuthBot 86 | // 87 | //Copyright (c) Microsoft Corporation 88 | //All rights reserved. 89 | // 90 | // MIT License: 91 | // Permission is hereby granted, free of charge, to any person obtaining 92 | // a copy of this software and associated documentation files (the 93 | // ""Software""), to deal in the Software without restriction, including 94 | // without limitation the rights to use, copy, modify, merge, publish, 95 | // distribute, sublicense, and/or sell copies of the Software, and to 96 | // permit persons to whom the Software is furnished to do so, subject to 97 | // the following conditions: 98 | 99 | 100 | 101 | 102 | // The above copyright notice and this permission notice shall be 103 | // included in all copies or substantial portions of the Software. 104 | 105 | 106 | 107 | 108 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, 109 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 110 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 111 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 112 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 113 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 114 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 115 | // 116 | //********************************************************* 117 | -------------------------------------------------------------------------------- /AuthBot/Models/MemoryTokenCacheMSAL.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See full license at the bottom of this file. 2 | using Microsoft.Identity.Client; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading; 7 | using System.Web; 8 | 9 | namespace AuthBot.Models 10 | { 11 | public class InMemoryTokenCacheMSAL : TokenCache 12 | { 13 | string CacheId = string.Empty; 14 | private Dictionary cache = new Dictionary(); 15 | 16 | public InMemoryTokenCacheMSAL() 17 | { 18 | CacheId = "_TokenCache"; 19 | this.AfterAccess = AfterAccessNotification; 20 | this.BeforeAccess = BeforeAccessNotification; 21 | Load(); 22 | } 23 | 24 | public InMemoryTokenCacheMSAL(byte[] tokenCache) 25 | { 26 | CacheId = "_TokenCache"; 27 | this.AfterAccess = AfterAccessNotification; 28 | this.BeforeAccess = BeforeAccessNotification; 29 | this.Deserialize(tokenCache); 30 | } 31 | 32 | public void SaveUserStateValue(string state) 33 | { 34 | cache[CacheId + "_state"] = state; 35 | } 36 | public string ReadUserStateValue() 37 | { 38 | string state = string.Empty; 39 | state=(string)cache[CacheId + "_state"]; 40 | return state; 41 | } 42 | public void Load() 43 | { 44 | if (cache.ContainsKey(CacheId)) 45 | this.Deserialize((byte[])cache[CacheId]); 46 | } 47 | 48 | public void Persist() 49 | { 50 | // Optimistically set HasStateChanged to false. We need to do it early to avoid losing changes made by a concurrent thread. 51 | this.HasStateChanged = false; 52 | 53 | // Reflect changes in the persistent store 54 | cache[CacheId] = this.Serialize(); 55 | } 56 | 57 | // Empties the persistent store. 58 | public override void Clear(string cliendId) 59 | { 60 | base.Clear(cliendId); 61 | cache.Remove(CacheId); 62 | } 63 | 64 | // Triggered right before ADAL needs to access the cache. 65 | // Reload the cache from the persistent store in case it changed since the last access. 66 | void BeforeAccessNotification(TokenCacheNotificationArgs args) 67 | { 68 | Load(); 69 | } 70 | 71 | // Triggered right after ADAL accessed the cache. 72 | void AfterAccessNotification(TokenCacheNotificationArgs args) 73 | { 74 | // if the access operation resulted in a cache update 75 | if (this.HasStateChanged) 76 | { 77 | Persist(); 78 | } 79 | } 80 | } 81 | 82 | } 83 | 84 | //********************************************************* 85 | // 86 | //AuthBot, https://github.com/microsoftdx/AuthBot 87 | // 88 | //Copyright (c) Microsoft Corporation 89 | //All rights reserved. 90 | // 91 | // MIT License: 92 | // Permission is hereby granted, free of charge, to any person obtaining 93 | // a copy of this software and associated documentation files (the 94 | // ""Software""), to deal in the Software without restriction, including 95 | // without limitation the rights to use, copy, modify, merge, publish, 96 | // distribute, sublicense, and/or sell copies of the Software, and to 97 | // permit persons to whom the Software is furnished to do so, subject to 98 | // the following conditions: 99 | 100 | 101 | 102 | 103 | // The above copyright notice and this permission notice shall be 104 | // included in all copies or substantial portions of the Software. 105 | 106 | 107 | 108 | 109 | // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND, 110 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 111 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 112 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 113 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 114 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 115 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 116 | // 117 | //********************************************************* 118 | -------------------------------------------------------------------------------- /AuthBot/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("AuthBot")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("AuthBot")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 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("b8ad59d3-c36d-4e18-b504-06871001bc8d")] 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("3.5.0.0")] 36 | [assembly: AssemblyFileVersion("3.5.0.0")] 37 | -------------------------------------------------------------------------------- /AuthBot/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 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /AuthBot/packages.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 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 - present Rick Van Rousselt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PrivacyPolicy.md: -------------------------------------------------------------------------------- 1 | I, Rick Van Rousselt, operate the SPAdminBot website(https://spadminbot.azurewebsites.net) and the SPAdminBot bot in Skype, DirectLine, Webchat and Microsoft Teams. This page informs you of my policies regarding the collection, use and disclosure of Personal Information I receive when you use my services. I use your Personal Information only for providing and improving the site and the chatbot. By using my services, you agree to the collection and use of information in accordance with this policy. 2 | 3 | #Information Collection And Use 4 | 5 | While using my services, I may ask you to provide me with certain personally identifiable information that can be used to contact or identify you. Personally identifiable information may include, but is not limited to your name and email ("Personal Information"). 6 | 7 | #Log Data 8 | 9 | Like many site operators, my service collects information that your system sends whenever you visit my service ("Log Data"). This Log Data may include information such as your computer's Internet Protocol ("IP") address, browser type, browser version, the pages of my service that you visit, the time and date of your visit, the time spent on those pages and other statistics. 10 | 11 | #Cookies 12 | 13 | Cookies are files with small amount of data, which may include an anonymous unique identifier. Cookies are sent to your browser from a web site and stored on your computer's hard drive. Like many sites, I use "cookies" to collect information. You can instruct your browser to refuse all cookies or to indicate when a cookie is being sent. However, if you do not accept cookies, you may not be able to use some portions of my service. 14 | 15 | #Security 16 | 17 | The security of your Personal Information is important to me, but remember that no method of transmission over the Internet, or method of electronic storage, is 100% secure. While I strive to use commercially acceptable means to protect your Personal Information, I cannot guarantee its absolute security. 18 | 19 | #Bot Framework 20 | 21 | My chatbot is enabled by Microsofts Bot Framework. Bot Framework is a set of web-services that enable intelligent services and connections using conversation channels you authorize. As a service provider, Microsoft will create a Bot Framework user profile and receive content you provide to my bot/service in order to enable the service and to help improve Microsoft services. For more information about Microsoft privacy policies please see their privacy statement here: http://go.microsoft.com/fwlink/?LinkId=521839. To report abuse when using a bot that uses Bot Framework to Microsoft, please visit the Microsoft Bot Framework website at https://www.botframework.com and use the Report Abuse link in the menu to contact Microsoft. 22 | 23 | #APIs 24 | 25 | Furthermore, SPAdminBot is enabled by the following APIs: 26 | - Microsoft Graph: for more information about the Microsoft Graph please visit [https://graph.microsoft.io/en-us/](https://graph.microsoft.io/en-us/) 27 | - AuthBot: Part of the code used in this bot is from the AuthBot. More information can be found here.[https://github.com/MicrosoftDX/AuthBot](https://github.com/MicrosoftDX/AuthBot) 28 | 29 | #Changes To This Privacy Policy 30 | 31 | This Privacy Policy is effective as of (add date) and will remain in effect except with respect to any changes in its provisions in the future, which will be in effect immediately after being posted on this page. I reserve the right to update or change my Privacy Policy at any time and you should check this Privacy Policy periodically. Your continued use of the Service after I post any modifications to the Privacy Policy on this page will constitute your acknowledgment of the modifications and your consent to abide and be bound by the modified Privacy Policy. If I make any material changes to this Privacy Policy, I will notify you either through the email address you have provided us, or by placing a prominent notice on my website 32 | 33 | #Contact 34 | 35 | If you have any questions about this Privacy Policy, please contact me: 36 | Rick Van Rousselt, Lindelsebaan 13, 3900 Overpelt - Belgium 37 | Rick.vanrousselt@outlook.com 38 | @RickVanRousselt 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SharePoint Administration Bot 2 | The SharePoint Admin Bot is an attempt to make the everyday routinous jobs that a SharePoint Online Administrator or Power User easier. 3 | Currently the features are limited but the goal is to make them grow. If the feature you want is not in there yet please submit a feature request or even better contribute and do a pull request. 4 | 5 | # Start to use the Bot 6 | To use the SharePoint Admin Bot you do not have to clone or download the code. You can just connect to it using the links below. 7 | The bot uses [LUIS.AI](https://www.luis.ai) to try and understand what you mean. Luis also has to learn so if your sentence is not recongized try to rephrase the question. 8 | 9 | + [Use the webchat](https://spadminbot.azurewebsites.net) 10 | + [Thru Skype](https://join.skype.com/bot/3b1b9f8d-3ee6-4bc1-a221-544b58140b74) 11 | + [MS Teams](https://teams.microsoft.com/l/chat/0/0?users=28:3b1b9f8d-3ee6-4bc1-a221-544b58140b74) 12 | 13 | ## If you want your own version of the SharePoint Admin Bot then you can follow the steps in the [wiki](https://github.com/RickVanRousselt/SharePointAdminBot/wiki/How-to-Install) 14 | 15 | ### Check out our [YouTube Channel](https://www.youtube.com/watch?v=Z3y2NhZZKrQ&index=3&list=PLJuydARUjhplEMoGyi1BqS5Vmvy2rm36T) to see how it works 16 | 17 | 18 | ## Current features 19 | ##### Get Site Collection properties 20 | Returns list of general properties from the Site Collection 21 | _Example Question: Get me information about my site collection_ 22 | ##### Get Web properties 23 | Returns list of general properties from the Rootweb of a Site Collection 24 | _Example Question: Get me information about my web_ 25 | ##### Create Site Collection 26 | Asks several question and then creates a Site Collection. 27 | _Example Question: Can you create me a new site collection_ 28 | ##### Reindex site 29 | Flags a site collection for reindexing 30 | _Example Question: Can you reindex a site_ 31 | 32 | 33 | 34 | # Contribute 35 | I would love if you would help contribute to this project. Not just writing code but a simple feature request is enough. 36 | 37 | 38 | # More Information 39 | Check out my [blog](https://www.rickvanrousselt.com/spadminbot/) or contact [Advantive](https://www.advantive.be/) for more information on the SharePoint Admin Bot. 40 | 41 | [![MIT license](https://img.shields.io/npm/l/express.svg)](https://github.com/RickVanRousselt/SharePointAdminBot/blob/master/LICENSE) 42 | 43 | 44 | ![alt text](https://www.advantive.nl/wordpress/wp-content/uploads/2016/08/logo_advantive.png "Advantive") 45 | -------------------------------------------------------------------------------- /SPAdminBot.json: -------------------------------------------------------------------------------- 1 | { 2 | "luis_schema_version": "1.3.1", 3 | "versionId": "0.1", 4 | "name": "SPAdminBot", 5 | "desc": "SharePoint Administration Bot", 6 | "culture": "en-us", 7 | "intents": [ 8 | { 9 | "name": "Common" 10 | }, 11 | { 12 | "name": "Create" 13 | }, 14 | { 15 | "name": "GetInfo" 16 | }, 17 | { 18 | "name": "Logout" 19 | }, 20 | { 21 | "name": "None" 22 | }, 23 | { 24 | "name": "ReIndex" 25 | } 26 | ], 27 | "entities": [ 28 | { 29 | "name": "SiteCollection" 30 | }, 31 | { 32 | "name": "Tenant" 33 | }, 34 | { 35 | "name": "URL" 36 | }, 37 | { 38 | "name": "Web" 39 | } 40 | ], 41 | "composites": [], 42 | "closedLists": [], 43 | "bing_entities": [], 44 | "actions": [], 45 | "model_features": [], 46 | "regex_features": [ 47 | { 48 | "name": "URL", 49 | "pattern": "https?:\\/\\/(www\\.)?[-a-zA-Z0-9@:%._\\+~#=]{2,256}\\.[a-z]{2,6}\\b([-a-zA-Z0-9@:%_\\+.~#?&//=]*)", 50 | "activated": true 51 | } 52 | ], 53 | "utterances": [ 54 | { 55 | "text": "g", 56 | "intent": "None", 57 | "entities": [] 58 | }, 59 | { 60 | "text": "logon", 61 | "intent": "None", 62 | "entities": [] 63 | }, 64 | { 65 | "text": "https://devkbcgroup.sharepoint.com", 66 | "intent": "None", 67 | "entities": [] 68 | }, 69 | { 70 | "text": "can you get me my tenant information", 71 | "intent": "GetInfo", 72 | "entities": [] 73 | }, 74 | { 75 | "text": "can you give me information about my site collection", 76 | "intent": "GetInfo", 77 | "entities": [ 78 | { 79 | "entity": "SiteCollection", 80 | "startPos": 7, 81 | "endPos": 7 82 | }, 83 | { 84 | "entity": "SiteCollection", 85 | "startPos": 8, 86 | "endPos": 8 87 | } 88 | ] 89 | }, 90 | { 91 | "text": "https://rivaro.sharepoint.com/", 92 | "intent": "GetInfo", 93 | "entities": [] 94 | }, 95 | { 96 | "text": "get information about my web", 97 | "intent": "GetInfo", 98 | "entities": [ 99 | { 100 | "entity": "Web", 101 | "startPos": 4, 102 | "endPos": 4 103 | } 104 | ] 105 | }, 106 | { 107 | "text": "what are the settings of my web", 108 | "intent": "GetInfo", 109 | "entities": [ 110 | { 111 | "entity": "Web", 112 | "startPos": 6, 113 | "endPos": 6 114 | } 115 | ] 116 | }, 117 | { 118 | "text": "what are the settings of my site", 119 | "intent": "GetInfo", 120 | "entities": [ 121 | { 122 | "entity": "SiteCollection", 123 | "startPos": 6, 124 | "endPos": 6 125 | } 126 | ] 127 | }, 128 | { 129 | "text": "an you get me my tenant information", 130 | "intent": "GetInfo", 131 | "entities": [] 132 | }, 133 | { 134 | "text": "list site collections", 135 | "intent": "GetInfo", 136 | "entities": [] 137 | }, 138 | { 139 | "text": "site info", 140 | "intent": "GetInfo", 141 | "entities": [] 142 | }, 143 | { 144 | "text": "get site collection", 145 | "intent": "GetInfo", 146 | "entities": [ 147 | { 148 | "entity": "SiteCollection", 149 | "startPos": 1, 150 | "endPos": 1 151 | }, 152 | { 153 | "entity": "SiteCollection", 154 | "startPos": 2, 155 | "endPos": 2 156 | } 157 | ] 158 | }, 159 | { 160 | "text": "get tenant info", 161 | "intent": "GetInfo", 162 | "entities": [] 163 | }, 164 | { 165 | "text": "get information about my site collection", 166 | "intent": "GetInfo", 167 | "entities": [ 168 | { 169 | "entity": "SiteCollection", 170 | "startPos": 4, 171 | "endPos": 4 172 | }, 173 | { 174 | "entity": "SiteCollection", 175 | "startPos": 5, 176 | "endPos": 5 177 | } 178 | ] 179 | }, 180 | { 181 | "text": "site collection info", 182 | "intent": "GetInfo", 183 | "entities": [ 184 | { 185 | "entity": "SiteCollection", 186 | "startPos": 0, 187 | "endPos": 0 188 | }, 189 | { 190 | "entity": "SiteCollection", 191 | "startPos": 1, 192 | "endPos": 1 193 | } 194 | ] 195 | }, 196 | { 197 | "text": "info", 198 | "intent": "GetInfo", 199 | "entities": [] 200 | }, 201 | { 202 | "text": "get me my tenant information", 203 | "intent": "GetInfo", 204 | "entities": [] 205 | }, 206 | { 207 | "text": "get information about my site", 208 | "intent": "GetInfo", 209 | "entities": [ 210 | { 211 | "entity": "SiteCollection", 212 | "startPos": 4, 213 | "endPos": 4 214 | } 215 | ] 216 | }, 217 | { 218 | "text": "get information about my site colleciton", 219 | "intent": "GetInfo", 220 | "entities": [ 221 | { 222 | "entity": "SiteCollection", 223 | "startPos": 4, 224 | "endPos": 4 225 | } 226 | ] 227 | }, 228 | { 229 | "text": "get site collection information", 230 | "intent": "GetInfo", 231 | "entities": [ 232 | { 233 | "entity": "SiteCollection", 234 | "startPos": 1, 235 | "endPos": 1 236 | }, 237 | { 238 | "entity": "SiteCollection", 239 | "startPos": 2, 240 | "endPos": 2 241 | } 242 | ] 243 | }, 244 | { 245 | "text": "get information about my site collectino", 246 | "intent": "GetInfo", 247 | "entities": [ 248 | { 249 | "entity": "SiteCollection", 250 | "startPos": 4, 251 | "endPos": 4 252 | } 253 | ] 254 | }, 255 | { 256 | "text": "create a new site collection", 257 | "intent": "Create", 258 | "entities": [ 259 | { 260 | "entity": "SiteCollection", 261 | "startPos": 3, 262 | "endPos": 3 263 | }, 264 | { 265 | "entity": "SiteCollection", 266 | "startPos": 4, 267 | "endPos": 4 268 | } 269 | ] 270 | }, 271 | { 272 | "text": "create site collection", 273 | "intent": "Create", 274 | "entities": [ 275 | { 276 | "entity": "SiteCollection", 277 | "startPos": 1, 278 | "endPos": 1 279 | }, 280 | { 281 | "entity": "SiteCollection", 282 | "startPos": 2, 283 | "endPos": 2 284 | } 285 | ] 286 | }, 287 | { 288 | "text": "logout", 289 | "intent": "Logout", 290 | "entities": [] 291 | }, 292 | { 293 | "text": "reset", 294 | "intent": "Logout", 295 | "entities": [] 296 | }, 297 | { 298 | "text": "log me out", 299 | "intent": "Logout", 300 | "entities": [] 301 | }, 302 | { 303 | "text": "logof", 304 | "intent": "Logout", 305 | "entities": [] 306 | }, 307 | { 308 | "text": "sign out", 309 | "intent": "Logout", 310 | "entities": [] 311 | }, 312 | { 313 | "text": "can you reindex my site collection", 314 | "intent": "ReIndex", 315 | "entities": [ 316 | { 317 | "entity": "SiteCollection", 318 | "startPos": 4, 319 | "endPos": 4 320 | }, 321 | { 322 | "entity": "SiteCollection", 323 | "startPos": 5, 324 | "endPos": 5 325 | } 326 | ] 327 | }, 328 | { 329 | "text": "hello", 330 | "intent": "Common", 331 | "entities": [] 332 | }, 333 | { 334 | "text": "hi", 335 | "intent": "Common", 336 | "entities": [] 337 | } 338 | ] 339 | } -------------------------------------------------------------------------------- /SharePointAdminBot.Infra/AiExceptionLogger.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Web.Http.ExceptionHandling; 3 | using Microsoft.ApplicationInsights; 4 | using Microsoft.ApplicationInsights.DataContracts; 5 | using Microsoft.Bot.Builder.Dialogs; 6 | using Newtonsoft.Json; 7 | 8 | namespace SharePointAdminBot.Infra 9 | { 10 | public class AiExceptionLogger : ExceptionLogger 11 | { 12 | public override void Log(ExceptionLoggerContext context) 13 | { 14 | if (context != null && context.Exception != null) 15 | { 16 | var ai = new TelemetryClient(); 17 | ai.TrackException(context.Exception); 18 | } 19 | base.Log(context); 20 | } 21 | } 22 | 23 | public static class TelemetryExtensions 24 | { 25 | public static TraceTelemetry CreateTraceTelemetry(this IDialogContext ctx, string message = null, IDictionary properties = null) 26 | { 27 | var t = new TraceTelemetry(message); 28 | t.Properties.Add("ConversationData", JsonConvert.SerializeObject(ctx.ConversationData)); 29 | t.Properties.Add("PrivateConversationData", JsonConvert.SerializeObject(ctx.PrivateConversationData)); 30 | t.Properties.Add("UserData", JsonConvert.SerializeObject(ctx.UserData)); 31 | 32 | var m = ctx.MakeMessage(); 33 | t.Properties.Add("ConversationId", m.Conversation.Id); 34 | t.Properties.Add("UserId", m.Recipient.Id); 35 | 36 | if (properties != null) 37 | { 38 | foreach (var p in properties) 39 | { 40 | t.Properties.Add(p); 41 | } 42 | } 43 | 44 | return t; 45 | } 46 | 47 | public static EventTelemetry CreateEventTelemetry(this IDialogContext ctx, string message = null, IDictionary properties = null) 48 | { 49 | var t = new EventTelemetry(message); 50 | t.Properties.Add("ConversationData", JsonConvert.SerializeObject(ctx.ConversationData)); 51 | t.Properties.Add("PrivateConversationData", JsonConvert.SerializeObject(ctx.PrivateConversationData)); 52 | t.Properties.Add("UserData", JsonConvert.SerializeObject(ctx.UserData)); 53 | 54 | var m = ctx.MakeMessage(); 55 | t.Properties.Add("ConversationId", m.Conversation.Id); 56 | t.Properties.Add("UserId", m.Recipient.Id); 57 | 58 | if (properties != null) 59 | { 60 | foreach (var p in properties) 61 | { 62 | t.Properties.Add(p); 63 | } 64 | } 65 | 66 | return t; 67 | } 68 | 69 | 70 | public static ExceptionTelemetry CreateExceptionTelemetry(this IDialogContext ctx, System.Exception ex, IDictionary properties = null) 71 | { 72 | var t = new ExceptionTelemetry(ex); 73 | t.Properties.Add("ConversationData", JsonConvert.SerializeObject(ctx.ConversationData)); 74 | t.Properties.Add("PrivateConversationData", JsonConvert.SerializeObject(ctx.PrivateConversationData)); 75 | t.Properties.Add("UserData", JsonConvert.SerializeObject(ctx.UserData)); 76 | 77 | var m = ctx.MakeMessage(); 78 | t.Properties.Add("ConversationId", m.Conversation.Id); 79 | t.Properties.Add("UserId", m.Recipient.Id); 80 | 81 | if (properties != null) 82 | { 83 | foreach (var p in properties) 84 | { 85 | t.Properties.Add(p); 86 | } 87 | } 88 | 89 | return t; 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /SharePointAdminBot.Infra/Create.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Web; 4 | using AuthBot.Models; 5 | using Microsoft.ApplicationInsights; 6 | using Microsoft.Online.SharePoint.TenantAdministration; 7 | using Microsoft.SharePoint.Client; 8 | using Newtonsoft.Json; 9 | using OfficeDevPnP.Core; 10 | using SharePointAdminBot.Infra.Forms; 11 | 12 | namespace SharePointAdminBot.Infra 13 | { 14 | public static class Create 15 | { 16 | private static readonly log4net.ILog Logger = log4net.LogManager.GetLogger("Create"); 17 | 18 | public static bool CreateSiteColleciton(AuthResult result, CreateSiteCollectionQuery formResult, string tenantUrl, string resourceId) 19 | { 20 | var telemetry = new TelemetryClient(); 21 | bool succes = false; 22 | var telProps = new Dictionary(); 23 | try 24 | { 25 | AuthenticationManager authManager = new AuthenticationManager(); 26 | using (ClientContext context = authManager.GetAzureADAccessTokenAuthenticatedContext(tenantUrl, result.AccessToken)) 27 | { 28 | telProps.Add("Create Site collection connection URL", tenantUrl); 29 | Tenant t = new Tenant(context); 30 | SiteCreationProperties props = new SiteCreationProperties 31 | { 32 | Url = 33 | $"https://{resourceId}.sharepoint.com/sites/{HttpContext.Current.Server.UrlEncode(formResult.Title)}", 34 | Title = formResult.Title, 35 | Owner = result.Upn, 36 | StorageMaximumLevel = formResult.Storage, 37 | UserCodeMaximumLevel = formResult.Resource, 38 | Template = "STS#0" 39 | }; 40 | 41 | 42 | switch (formResult.SiteTemplate) 43 | { 44 | case SiteTemplate.TeamSite: 45 | props.Template = "STS#0"; 46 | break; 47 | case SiteTemplate.CommunitySite: 48 | props.Template = "COMMUNITY#0"; 49 | break; 50 | case SiteTemplate.WikiSite: 51 | props.Template = "WIKI#0"; 52 | break; 53 | } 54 | telProps.Add("Create site props", JsonConvert.SerializeObject(props)); 55 | telemetry.TrackEvent("Create site collection", telProps); 56 | t.CreateSite(props); 57 | context.ExecuteQuery(); 58 | succes = true; 59 | } 60 | } 61 | catch (Exception ex) 62 | { 63 | //TODO return ex message 64 | telemetry.TrackException(ex,telProps); 65 | } 66 | return succes; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /SharePointAdminBot.Infra/Forms/AskForUrlQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Bot.Builder.FormFlow; 3 | 4 | namespace SharePointAdminBot.Infra.Forms 5 | { 6 | [Serializable] 7 | public class AskForUrlQuery 8 | { 9 | [Prompt("Please enter the {&}")] 10 | public string Url { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SharePointAdminBot.Infra/Forms/CreateSiteCollectionQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Bot.Builder.FormFlow; 3 | 4 | namespace SharePointAdminBot.Infra.Forms 5 | { 6 | [Serializable] 7 | public class CreateSiteCollectionQuery 8 | { 9 | 10 | //[Prompt("Please enter the {&} of the site collection you want to create")] 11 | //public string Url { get; set; } 12 | 13 | [Prompt("What is the {&}?")] 14 | public string Title { get; set; } 15 | 16 | //[Prompt("What's the email address of the {&}?")] 17 | //public string Owner { get; set; } 18 | 19 | [Prompt("What's the {&} amount in MB?")] 20 | public long Storage { get; set; } 21 | 22 | [Prompt("What's the {&} amount?")] 23 | public long Resource { get; set; } 24 | 25 | [Prompt("What {&} should the site be? {||}", ChoiceFormat = "{1}")] 26 | public SiteTemplate SiteTemplate { get; set; } 27 | 28 | 29 | } 30 | 31 | public enum SiteTemplate 32 | { 33 | Ignore, 34 | WikiSite, 35 | CommunitySite, 36 | TeamSite 37 | }; 38 | } -------------------------------------------------------------------------------- /SharePointAdminBot.Infra/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("SharePointAdminBot.Infra")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SharePointAdminBot.Infra")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 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("0c62493b-6612-473e-b1ff-6098ddab441a")] 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 | -------------------------------------------------------------------------------- /SharePointAdminBot.Infra/SharePointAdminBot.Infra.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {0C62493B-6612-473E-B1FF-6098DDAB441A} 8 | Library 9 | Properties 10 | SharePointAdminBot.Infra 11 | SharePointAdminBot.Infra 12 | v4.6 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | ..\packages\Autofac.3.5.2\lib\net40\Autofac.dll 36 | True 37 | 38 | 39 | ..\packages\Chronic.Signed.0.3.2\lib\net40\Chronic.dll 40 | True 41 | 42 | 43 | ..\packages\log4net.2.0.7\lib\net45-full\log4net.dll 44 | True 45 | 46 | 47 | ..\packages\Microsoft.ApplicationInsights.2.2.0\lib\net46\Microsoft.ApplicationInsights.dll 48 | True 49 | 50 | 51 | ..\packages\Microsoft.ApplicationInsights.Log4NetAppender.2.2.0\lib\net45\Microsoft.ApplicationInsights.Log4NetAppender.dll 52 | True 53 | 54 | 55 | ..\packages\Microsoft.Azure.ActiveDirectory.GraphClient.2.1.0\lib\portable-net4+sl5+win+wpa+wp8\Microsoft.Azure.ActiveDirectory.GraphClient.dll 56 | True 57 | 58 | 59 | ..\packages\Microsoft.Azure.KeyVault.Core.1.0.0\lib\net40\Microsoft.Azure.KeyVault.Core.dll 60 | True 61 | 62 | 63 | ..\packages\Microsoft.Bot.Builder.3.5.3\lib\net46\Microsoft.Bot.Builder.dll 64 | True 65 | 66 | 67 | ..\packages\Microsoft.Bot.Builder.3.5.3\lib\net46\Microsoft.Bot.Builder.Autofac.dll 68 | True 69 | 70 | 71 | ..\packages\Microsoft.Bot.Builder.3.5.3\lib\net46\Microsoft.Bot.Connector.dll 72 | True 73 | 74 | 75 | ..\packages\Microsoft.Data.Edm.5.6.4\lib\net40\Microsoft.Data.Edm.dll 76 | True 77 | 78 | 79 | ..\packages\Microsoft.Data.OData.5.6.4\lib\net40\Microsoft.Data.OData.dll 80 | True 81 | 82 | 83 | ..\packages\Microsoft.Data.Services.Client.5.6.4\lib\net40\Microsoft.Data.Services.Client.dll 84 | True 85 | 86 | 87 | ..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.1.0.0\lib\netstandard1.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll 88 | True 89 | 90 | 91 | ..\packages\Microsoft.Extensions.Options.1.0.0\lib\netstandard1.0\Microsoft.Extensions.Options.dll 92 | True 93 | 94 | 95 | ..\packages\Microsoft.Extensions.Primitives.1.0.0\lib\netstandard1.0\Microsoft.Extensions.Primitives.dll 96 | True 97 | 98 | 99 | ..\packages\Microsoft.Extensions.WebEncoders.1.0.0\lib\netstandard1.0\Microsoft.Extensions.WebEncoders.dll 100 | True 101 | 102 | 103 | ..\packages\Microsoft.Graph.1.2.0\lib\portable45-net45+win8+wpa81\Microsoft.Graph.dll 104 | True 105 | 106 | 107 | ..\packages\Microsoft.Graph.Core.1.3.0\lib\portable45-net45+win8+wpa81\Microsoft.Graph.Core.dll 108 | True 109 | 110 | 111 | ..\packages\Microsoft.IdentityModel.6.1.7600.16394\lib\net35\Microsoft.IdentityModel.dll 112 | True 113 | 114 | 115 | ..\packages\Microsoft.IdentityModel.Protocol.Extensions.1.0.2.206221351\lib\net45\Microsoft.IdentityModel.Protocol.Extensions.dll 116 | True 117 | 118 | 119 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.6112.1200\lib\net45\Microsoft.Office.Client.Policy.dll 120 | True 121 | 122 | 123 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.6112.1200\lib\net45\Microsoft.Office.Client.TranslationServices.dll 124 | True 125 | 126 | 127 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.6112.1200\lib\net45\Microsoft.Office.SharePoint.Tools.dll 128 | True 129 | 130 | 131 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.6112.1200\lib\net45\Microsoft.Online.SharePoint.Client.Tenant.dll 132 | True 133 | 134 | 135 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.6112.1200\lib\net45\Microsoft.ProjectServer.Client.dll 136 | True 137 | 138 | 139 | ..\packages\Microsoft.Rest.ClientRuntime.2.3.2\lib\net45\Microsoft.Rest.ClientRuntime.dll 140 | True 141 | 142 | 143 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.6112.1200\lib\net45\Microsoft.SharePoint.Client.dll 144 | True 145 | 146 | 147 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.6112.1200\lib\net45\Microsoft.SharePoint.Client.DocumentManagement.dll 148 | True 149 | 150 | 151 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.6112.1200\lib\net45\Microsoft.SharePoint.Client.Publishing.dll 152 | True 153 | 154 | 155 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.6112.1200\lib\net45\Microsoft.SharePoint.Client.Runtime.dll 156 | True 157 | 158 | 159 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.6112.1200\lib\net45\Microsoft.SharePoint.Client.Runtime.Windows.dll 160 | True 161 | 162 | 163 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.6112.1200\lib\net45\Microsoft.SharePoint.Client.Search.dll 164 | True 165 | 166 | 167 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.6112.1200\lib\net45\Microsoft.SharePoint.Client.Search.Applications.dll 168 | True 169 | 170 | 171 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.6112.1200\lib\net45\Microsoft.SharePoint.Client.Taxonomy.dll 172 | True 173 | 174 | 175 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.6112.1200\lib\net45\Microsoft.SharePoint.Client.UserProfiles.dll 176 | True 177 | 178 | 179 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.6112.1200\lib\net45\Microsoft.SharePoint.Client.WorkflowServices.dll 180 | True 181 | 182 | 183 | ..\packages\WindowsAzure.Storage.7.0.0\lib\net40\Microsoft.WindowsAzure.Storage.dll 184 | True 185 | 186 | 187 | ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll 188 | True 189 | 190 | 191 | ..\packages\SharePointPnPCoreOnline.2.12.1702.0\lib\net45\OfficeDevPnP.Core.dll 192 | True 193 | 194 | 195 | ..\packages\SharePointPnP.IdentityModel.Extensions.1.2.0\lib\net45\SharePointPnP.IdentityModel.Extensions.dll 196 | True 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | ..\packages\System.IdentityModel.Tokens.Jwt.4.0.2.206221351\lib\net45\System.IdentityModel.Tokens.Jwt.dll 206 | True 207 | 208 | 209 | 210 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll 211 | True 212 | 213 | 214 | 215 | 216 | 217 | ..\packages\System.Spatial.5.6.4\lib\net40\System.Spatial.dll 218 | True 219 | 220 | 221 | ..\packages\System.Text.Encodings.Web.4.0.0\lib\netstandard1.0\System.Text.Encodings.Web.dll 222 | True 223 | 224 | 225 | 226 | 227 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll 228 | True 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | {b8ad59d3-c36d-4e18-b504-06871001bc8d} 252 | AuthBot 253 | 254 | 255 | 256 | 263 | -------------------------------------------------------------------------------- /SharePointAdminBot.Infra/SharePointInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Reflection; 4 | using AuthBot.Models; 5 | using Microsoft.ApplicationInsights; 6 | using Microsoft.SharePoint.Client; 7 | using OfficeDevPnP.Core; 8 | 9 | namespace SharePointAdminBot.Infra 10 | { 11 | public static class SharePointInfo 12 | { 13 | public static List GetSiteProperties(AuthResult result, string url) 14 | { 15 | var telemetry = new TelemetryClient(); 16 | var telProps = new Dictionary(); 17 | try 18 | { 19 | telemetry.TrackTrace("Get Site Properties called"); 20 | telProps.Add("Url", url); 21 | telemetry.TrackEvent("Get Site Properties", telProps); 22 | AuthenticationManager authManager = new AuthenticationManager(); 23 | Site site; 24 | var propertyList = new List(); 25 | using (ClientContext context = authManager.GetAzureADAccessTokenAuthenticatedContext(url, result.AccessToken)) 26 | { 27 | site = context.Site; 28 | context.Load(site, x => x.AllowDesigner, x => x.CompatibilityLevel, x => x.Id, x => x.AllowCreateDeclarativeWorkflow, x => x.AllowMasterPageEditing, x => x.AllowRevertFromTemplate, x => x.AllowSaveDeclarativeWorkflowAsTemplate, x => x.AllowSavePublishDeclarativeWorkflow, x => x.AllowSelfServiceUpgrade, x => x.AllowSelfServiceUpgradeEvaluation,x => x.AuditLogTrimmingRetention, x => x.CanUpgrade, x => x.Classification, x => x.DisableAppViews, x => x.ExternalSharingTipsEnabled, x => x.Url); 29 | context.ExecuteQuery(); 30 | } 31 | 32 | var siteType = site.GetType(); 33 | BindingFlags flags = BindingFlags.Public | BindingFlags.Instance; 34 | var properties = siteType.GetProperties(flags); 35 | foreach (var propertyInfo in properties) 36 | { 37 | if (site.IsPropertyAvailable(propertyInfo.Name)) 38 | { 39 | propertyList.Add($"{propertyInfo.Name}: {propertyInfo.GetValue(site, null)}"); 40 | } 41 | } 42 | return propertyList; 43 | } 44 | catch (Exception ex) 45 | { 46 | telemetry.TrackException(ex); 47 | return null; 48 | } 49 | 50 | } 51 | 52 | public static List GetWebProperties(AuthResult result, string url) 53 | { 54 | var telemetry = new TelemetryClient(); 55 | var telProps = new Dictionary(); 56 | try 57 | { 58 | telemetry.TrackTrace("Get web Properties called"); 59 | telProps.Add("Url", url); 60 | telemetry.TrackEvent("Get web Properties", telProps); 61 | AuthenticationManager authManager = new AuthenticationManager(); 62 | Web site; 63 | var propertyList = new List(); 64 | using (ClientContext context = authManager.GetAzureADAccessTokenAuthenticatedContext(url, result.AccessToken)) 65 | { 66 | site = context.Site.RootWeb; 67 | context.Load(site, x => x.AlternateCssUrl, x => x.Title, x => x.Id, x => x.Description, x => x.Created, x => x.EnableMinimalDownload, x => x.CustomMasterUrl, x => x.IsMultilingual, x => x.Language, x => x.QuickLaunchEnabled, x => x.WebTemplate, x => x.UIVersion); 68 | context.ExecuteQuery(); 69 | } 70 | 71 | var siteType = site.GetType(); 72 | BindingFlags flags = BindingFlags.Public | BindingFlags.Instance; 73 | var properties = siteType.GetProperties(flags); 74 | foreach (var propertyInfo in properties) 75 | { 76 | if (site.IsPropertyAvailable(propertyInfo.Name)) 77 | { 78 | propertyList.Add($"{propertyInfo.Name}: {propertyInfo.GetValue(site, null)}"); 79 | } 80 | } 81 | return propertyList; 82 | } 83 | catch (Exception ex) 84 | { 85 | telemetry.TrackException(ex); 86 | return null; 87 | } 88 | 89 | } 90 | 91 | public static bool ReIndexSiteCollection(AuthResult result, string url) 92 | { 93 | var telemetry = new TelemetryClient(); 94 | try 95 | { 96 | AuthenticationManager authManager = new AuthenticationManager(); 97 | using ( 98 | ClientContext context = authManager.GetAzureADAccessTokenAuthenticatedContext(url, 99 | result.AccessToken)) 100 | { 101 | context.Web.ReIndexWeb(); 102 | } 103 | return true; 104 | } 105 | catch (Exception ex) 106 | { 107 | telemetry.TrackException(ex); 108 | return false; 109 | } 110 | 111 | 112 | } 113 | 114 | public static string GetTenantId(string token) 115 | { 116 | return null; 117 | 118 | } 119 | 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /SharePointAdminBot.Infra/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 | 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 | -------------------------------------------------------------------------------- /SharePointAdminBot.Infra/packages.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 | -------------------------------------------------------------------------------- /SharePointAdminBot.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharePointAdminBot", "SharePointAdminBot\SharePointAdminBot.csproj", "{A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharePointAdminBot.Infra", "SharePointAdminBot.Infra\SharePointAdminBot.Infra.csproj", "{0C62493B-6612-473E-B1FF-6098DDAB441A}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AuthBot", "AuthBot\AuthBot.csproj", "{B8AD59D3-C36D-4E18-B504-06871001BC8D}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {0C62493B-6612-473E-B1FF-6098DDAB441A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {0C62493B-6612-473E-B1FF-6098DDAB441A}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {0C62493B-6612-473E-B1FF-6098DDAB441A}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {0C62493B-6612-473E-B1FF-6098DDAB441A}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {B8AD59D3-C36D-4E18-B504-06871001BC8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {B8AD59D3-C36D-4E18-B504-06871001BC8D}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {B8AD59D3-C36D-4E18-B504-06871001BC8D}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {B8AD59D3-C36D-4E18-B504-06871001BC8D}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /SharePointAdminBot/AppInsightsInitializer.cs: -------------------------------------------------------------------------------- 1 | using System.Configuration; 2 | using System.Reflection; 3 | using Microsoft.ApplicationInsights.Channel; 4 | 5 | namespace SharePointAdminBot 6 | { 7 | public class AppInsightsInitializer : Microsoft.ApplicationInsights.Extensibility.ITelemetryInitializer 8 | { 9 | public void Initialize(ITelemetry telemetry) 10 | { 11 | telemetry.Context.Component.Version = Assembly.GetExecutingAssembly().GetName().Version.ToString(); 12 | telemetry.Context.Properties["tags"] = "SPAdminBot"; 13 | telemetry.Context.InstrumentationKey = ConfigurationManager.AppSettings["iKey"]; 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /SharePointAdminBot/App_Start/WebApiConfig.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using Newtonsoft.Json.Serialization; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Web.Http; 7 | using System.Web.Http.ExceptionHandling; 8 | using SharePointAdminBot.Infra; 9 | 10 | namespace SharePointAdminBot 11 | { 12 | public static class WebApiConfig 13 | { 14 | public static void Register(HttpConfiguration config) 15 | { 16 | // Json settings 17 | config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; 18 | config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); 19 | config.Formatters.JsonFormatter.SerializerSettings.Formatting = Formatting.Indented; 20 | JsonConvert.DefaultSettings = () => new JsonSerializerSettings() 21 | { 22 | ContractResolver = new CamelCasePropertyNamesContractResolver(), 23 | Formatting = Newtonsoft.Json.Formatting.Indented, 24 | NullValueHandling = NullValueHandling.Ignore, 25 | }; 26 | 27 | // Web API configuration and services 28 | 29 | // Web API routes 30 | config.MapHttpAttributeRoutes(); 31 | 32 | config.Routes.MapHttpRoute( 33 | name: "DefaultApi", 34 | routeTemplate: "api/{controller}/{id}", 35 | defaults: new { id = RouteParameter.Optional } 36 | ); 37 | 38 | config.Services.Add(typeof(IExceptionLogger), new AiExceptionLogger()); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /SharePointAdminBot/ApplicationInsights.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 00000000-0000-0000-0000-000000000000 4 | 5 | 6 | 7 | 5 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 19 | search|spider|crawl|Bot|Monitor|AlwaysOn 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 61 | System.Web.Handlers.TransferRequestHandler 62 | Microsoft.VisualStudio.Web.PageInspector.Runtime.Tracing.RequestDataHttpHandler 63 | System.Web.StaticFileHandler 64 | System.Web.Handlers.AssemblyResourceLoader 65 | System.Web.Optimization.BundleHandler 66 | System.Web.Script.Services.ScriptHandlerFactory 67 | System.Web.Handlers.TraceHandler 68 | System.Web.Services.Discovery.DiscoveryRequestHandler 69 | System.Web.HttpDebugHandler 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /SharePointAdminBot/Controllers/MessagesController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Net; 5 | using System.Net.Http; 6 | using System.Threading.Tasks; 7 | using System.Web.Http; 8 | using Microsoft.ApplicationInsights; 9 | using Microsoft.Bot.Builder.Dialogs; 10 | using Microsoft.Bot.Connector; 11 | using Newtonsoft.Json; 12 | using SharePointAdminBot.Dialogs; 13 | 14 | namespace SharePointAdminBot.Controllers 15 | { 16 | [BotAuthentication] 17 | public class MessagesController : ApiController 18 | { 19 | 20 | /// 21 | /// POST: api/Messages 22 | /// Receive a message from a user and reply to it 23 | /// 24 | public async Task Post([FromBody]Activity activity) 25 | { 26 | var telemetry = new TelemetryClient(); 27 | if (activity != null && activity.GetActivityType() == ActivityTypes.Message) 28 | { 29 | try 30 | { 31 | telemetry.TrackTrace($"Entering POST {JsonConvert.SerializeObject(activity)}"); 32 | await Conversation.SendAsync(activity, () => new MasterDialog()); 33 | } 34 | catch (Exception ex) 35 | { 36 | telemetry.TrackException(ex); 37 | ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl)); 38 | Activity reply = activity.CreateReply("Sorry something went wrong. Please try again later or log an issue https://github.com/RickVanRousselt/SharePointAdminBot"); 39 | connector.Conversations.SendToConversation(reply); 40 | } 41 | } 42 | else 43 | { 44 | await HandleSystemMessage(activity); 45 | } 46 | return new HttpResponseMessage(HttpStatusCode.Accepted); 47 | } 48 | 49 | private async Task HandleSystemMessage(Activity message) 50 | { 51 | WebApiApplication.Telemetry.TrackEvent(@"SystemMessage", new Dictionary { { @"Type", message.Type } }); 52 | 53 | if (message.Type == ActivityTypes.DeleteUserData) 54 | { 55 | // Implement user deletion here 56 | // If we handle user deletion, return a real message 57 | } 58 | else if (message.Type == ActivityTypes.ConversationUpdate) 59 | { 60 | if (message.MembersAdded.Any()) 61 | { 62 | var newMembers = message.MembersAdded?.Where(t => t.Id != message.Recipient.Id); 63 | if (newMembers != null) 64 | foreach (var newMember in newMembers) 65 | { 66 | var telemetry = new TelemetryClient(); 67 | telemetry.TrackTrace($"New member added to chat: {newMember.Name}"); 68 | ConnectorClient connector = new ConnectorClient(new Uri(message.ServiceUrl)); 69 | StateClient stateClient = message.GetStateClient(); 70 | BotData conversationData = await stateClient.BotState.GetConversationDataAsync(message.ChannelId, message.From.Id); 71 | conversationData.SetProperty("Welcome", true); 72 | Activity reply = message.CreateReply("Hi I'm the SharePoint Admin Bot"); 73 | await connector.Conversations.SendToConversationAsync(reply); 74 | } 75 | } 76 | } 77 | else if (message.Type == ActivityTypes.ContactRelationUpdate) 78 | { 79 | // Handle add/remove from contact lists 80 | // Activity.From + Activity.Action represent what happened 81 | } 82 | else if (message.Type == ActivityTypes.Typing) 83 | { 84 | // Handle knowing tha the user is typing 85 | } 86 | else if (message.Type == ActivityTypes.Ping) 87 | { 88 | } 89 | 90 | return null; 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /SharePointAdminBot/Dialogs/FormBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Bot.Builder.Dialogs; 3 | using Microsoft.Bot.Builder.FormFlow; 4 | using SharePointAdminBot.Infra.Forms; 5 | 6 | namespace SharePointAdminBot.Dialogs 7 | { 8 | [Serializable] 9 | public class FormBuilder 10 | { 11 | public IForm BuildCreateSiteColForm() 12 | { 13 | OnCompletionAsyncDelegate processSiteCollectionQuery = async (context, state) => 14 | { 15 | await context.PostAsync($"Sending request for site collection creation.. Just a moment please"); 16 | }; 17 | 18 | return new FormBuilder() 19 | .Field(nameof(CreateSiteCollectionQuery.Title)) 20 | .Message("Starting the creation of the site collection") 21 | .AddRemainingFields() 22 | .OnCompletion(processSiteCollectionQuery) 23 | .Build(); 24 | } 25 | 26 | public IForm AskForUrl() 27 | { 28 | OnCompletionAsyncDelegate processAskForUrlQuery = async (context, state) => 29 | { 30 | await context.PostAsync($"Processing...."); 31 | }; 32 | 33 | return new FormBuilder() 34 | .Field(nameof(AskForUrlQuery.Url)) 35 | .OnCompletion(processAskForUrlQuery) 36 | .AddRemainingFields() 37 | .Build(); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /SharePointAdminBot/Dialogs/MasterDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using AuthBot; 6 | using AuthBot.Dialogs; 7 | using Microsoft.Bot.Builder.Dialogs; 8 | using Microsoft.Bot.Connector; 9 | using System.Configuration; 10 | using Newtonsoft.Json; 11 | using SharePointAdminBot.Infra; 12 | 13 | namespace SharePointAdminBot.Dialogs 14 | { 15 | [Serializable] 16 | public class MasterDialog : IDialog 17 | { 18 | private string _resourceId = ConfigurationManager.AppSettings["ActiveDirectory.ResourceId"]; 19 | 20 | public async Task StartAsync(IDialogContext context) 21 | { 22 | context.Wait(MessageReceivedAsync); 23 | } 24 | 25 | public virtual async Task MessageReceivedAsync(IDialogContext context, IAwaitable item) 26 | { 27 | var message = await item; 28 | WebApiApplication.Telemetry.TrackTrace(context.CreateTraceTelemetry( 29 | nameof(MessageReceivedAsync), 30 | new Dictionary { { "message", JsonConvert.SerializeObject(message) } })); 31 | 32 | if (message.Text == "logout" || message.Text == "reset") 33 | { 34 | context.UserData.RemoveValue("ResourceId"); 35 | _resourceId = ConfigurationManager.AppSettings["ActiveDirectory.ResourceId"]; 36 | await context.Logout(); 37 | context.Wait(MessageReceivedAsync); 38 | } 39 | else 40 | { 41 | if (string.IsNullOrEmpty(await context.GetAccessToken(ConfigurationManager.AppSettings["ActiveDirectory.ResourceId"]))) 42 | { 43 | var measuredEvent = context.CreateEventTelemetry(@"Login with Graph URL"); 44 | var timer = new System.Diagnostics.Stopwatch(); 45 | timer.Start(); 46 | try 47 | { 48 | string reply = $"First we need to authenticate you"; 49 | await context.PostAsync(reply); 50 | await 51 | context.Forward( 52 | new AzureAuthDialog(ConfigurationManager.AppSettings["ActiveDirectory.ResourceId"]), 53 | ResumeAfterAuth, message, CancellationToken.None); 54 | } 55 | catch (Exception ex) 56 | { 57 | measuredEvent.Properties.Add("exception", ex.ToString()); 58 | WebApiApplication.Telemetry.TrackException(context.CreateExceptionTelemetry(ex)); 59 | } 60 | finally 61 | { 62 | timer.Stop(); 63 | measuredEvent.Metrics.Add(@"timeTakenMs", timer.ElapsedMilliseconds); 64 | WebApiApplication.Telemetry.TrackEvent(measuredEvent); 65 | } 66 | } 67 | else 68 | { 69 | try 70 | { 71 | var spUrl = $"https://{_resourceId}.sharepoint.com"; 72 | WebApiApplication.Telemetry.TrackEvent(context.CreateEventTelemetry($"SPUrl: {spUrl}")); 73 | if (string.IsNullOrEmpty(await context.GetAccessToken(spUrl))) 74 | { 75 | await 76 | context.Forward( 77 | new AzureAuthDialog(ConfigurationManager.AppSettings["ActiveDirectory.ResourceId"]), 78 | ResumeAfterAuth, message, CancellationToken.None); 79 | } 80 | else 81 | { 82 | WebApiApplication.Telemetry.TrackEvent(context.CreateEventTelemetry(@"Calling RootLuisDialog")); 83 | await context.Forward(new RootLuisDialog(), null, message, CancellationToken.None); 84 | } 85 | 86 | 87 | } 88 | catch (Exception ex) 89 | { 90 | WebApiApplication.Telemetry.TrackException(context.CreateExceptionTelemetry(ex)); 91 | WebApiApplication.Telemetry.TrackEvent(context.CreateEventTelemetry(@"Error in masterdialog forwarding to Luis")); 92 | string reply = $"Sorry something went wrong"; 93 | await context.PostAsync(reply); 94 | context.Wait(MessageReceivedAsync); 95 | } 96 | } 97 | 98 | } 99 | 100 | } 101 | 102 | private async Task ResumeAfterAuth(IDialogContext context, IAwaitable result) 103 | { 104 | var message = await result; 105 | var authResult = context.GetAuthResult(); 106 | if (authResult != null) 107 | { 108 | var domain = authResult.Upn.Split('@')[1].Split('.')[0]; 109 | context.UserData.SetValue("ResourceId", domain); 110 | _resourceId = domain; 111 | } 112 | await context.PostAsync(message); 113 | await context.PostAsync("What would you like me to do?"); 114 | context.Wait(MessageReceivedAsync); 115 | } 116 | } 117 | } 118 | 119 | -------------------------------------------------------------------------------- /SharePointAdminBot/Dialogs/RootLuisDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Linq; 5 | using System.Text.RegularExpressions; 6 | using System.Threading.Tasks; 7 | using AuthBot; 8 | using AuthBot.Models; 9 | using Microsoft.Bot.Builder.Dialogs; 10 | using Microsoft.Bot.Builder.FormFlow; 11 | using Microsoft.Bot.Builder.Luis; 12 | using Microsoft.Bot.Builder.Luis.Models; 13 | using Newtonsoft.Json; 14 | using SharePointAdminBot.Infra; 15 | using SharePointAdminBot.Infra.Forms; 16 | 17 | namespace SharePointAdminBot.Dialogs 18 | { 19 | [Serializable] 20 | [LuisModel("c75d7bef-7f85-4ac5-a22e-0b78de2c7328", "863224eec48243e6b163c4bcbdd1a4c8")] 21 | public class RootLuisDialog : LuisDialog 22 | { 23 | private string _resourceId; 24 | private AuthResult _authResult; 25 | private readonly FormBuilder _formBuilder = new FormBuilder(); 26 | 27 | 28 | [LuisIntent("")] 29 | [LuisIntent("None")] 30 | public async Task None(IDialogContext context, LuisResult result) 31 | { 32 | string message = $"Sorry I did not understand: " + string.Join(", ", result.Intents.Select(i => i.Intent)); 33 | WebApiApplication.Telemetry.TrackTrace(context.CreateTraceTelemetry(nameof(None),new Dictionary { { "No intent found by luis", JsonConvert.SerializeObject(result) } })); 34 | await context.PostAsync(message); 35 | context.Wait(MessageReceived); 36 | } 37 | 38 | [LuisIntent("GetInfo")] 39 | public async Task GetSiteInfo(IDialogContext context, LuisResult result) 40 | { 41 | WebApiApplication.Telemetry.TrackTrace(context.CreateTraceTelemetry(nameof(GetSiteInfo), new Dictionary { { "GetInfo found by LUIS:", JsonConvert.SerializeObject(result) } })); 42 | var createUrlDialog = FormDialog.FromForm(_formBuilder.AskForUrl, FormOptions.PromptInStart); 43 | EntityRecommendation entity; 44 | if (result.TryFindEntity("SiteCollection", out entity)) 45 | { 46 | context.Call(createUrlDialog, GetSiteCollectionInfo); 47 | } 48 | else { context.Call(createUrlDialog, GetWebInfo); } 49 | } 50 | 51 | [LuisIntent("Create")] 52 | public async Task CreateSiteCollection(IDialogContext context, LuisResult result) 53 | { 54 | WebApiApplication.Telemetry.TrackTrace(context.CreateTraceTelemetry(nameof(CreateSiteCollection), new Dictionary { { "Create found by LUIS:", JsonConvert.SerializeObject(result) } })); 55 | var createSiteColFormDialog = FormDialog.FromForm(_formBuilder.BuildCreateSiteColForm, FormOptions.PromptInStart); 56 | context.Call(createSiteColFormDialog, AfterUrlProvided); 57 | } 58 | 59 | [LuisIntent("Logout")] 60 | public async Task Logout(IDialogContext context, LuisResult result) 61 | { 62 | WebApiApplication.Telemetry.TrackTrace(context.CreateTraceTelemetry(nameof(Logout), new Dictionary { { "Logout found by LUIS:", JsonConvert.SerializeObject(result) } })); 63 | context.UserData.RemoveValue("ResourceId"); 64 | _resourceId = ConfigurationManager.AppSettings["ActiveDirectory.ResourceId"]; 65 | await context.Logout(); 66 | context.Wait(MessageReceived); 67 | } 68 | 69 | [LuisIntent("ReIndex")] 70 | public async Task ReIndex(IDialogContext context, LuisResult result) 71 | { 72 | WebApiApplication.Telemetry.TrackTrace(context.CreateTraceTelemetry(nameof(ReIndex), new Dictionary { { "ReIndex found by LUIS:", JsonConvert.SerializeObject(result) } })); 73 | var createUrlDialog = FormDialog.FromForm(_formBuilder.AskForUrl, FormOptions.PromptInStart); 74 | context.Call(createUrlDialog, ReindexSite); 75 | } 76 | 77 | private async Task ReindexSite(IDialogContext context, IAwaitable result) 78 | { 79 | var formResults = await result; 80 | var url = formResults.Url; 81 | if (context.Activity.ChannelId == "skype") 82 | { 83 | url = Helpers.ParseAnchorTag(formResults.Url); 84 | } 85 | 86 | await context.GetAccessToken(url); 87 | context.UserData.TryGetValue(ContextConstants.AuthResultKey, out _authResult); 88 | 89 | var success = SharePointInfo.ReIndexSiteCollection(_authResult, url); 90 | if (success) 91 | { 92 | string message = $"Reindexing triggered. What's next?"; 93 | await context.PostAsync(message); 94 | } 95 | else 96 | { 97 | string message = $"Request for reindex went wrong"; 98 | await context.PostAsync(message); 99 | } 100 | context.Wait(MessageReceived); 101 | } 102 | 103 | private async Task GetSiteCollectionInfo(IDialogContext context, IAwaitable result) 104 | { 105 | var formResults = await result; 106 | var url = formResults.Url; 107 | if (context.Activity.ChannelId == "skype") 108 | { 109 | url = Helpers.ParseAnchorTag(formResults.Url); 110 | } 111 | 112 | await context.GetAccessToken(url); 113 | context.UserData.TryGetValue(ContextConstants.AuthResultKey, out _authResult); 114 | 115 | var returnedItems = SharePointInfo.GetSiteProperties(_authResult, url); 116 | 117 | foreach (var answer in returnedItems) 118 | { 119 | var message = answer; 120 | await context.PostAsync(message); 121 | } 122 | var finalMessage = $"What's next?"; 123 | await context.PostAsync(finalMessage); 124 | context.Wait(MessageReceived); 125 | } 126 | 127 | private async Task GetWebInfo(IDialogContext context, IAwaitable result) 128 | { 129 | var formResults = await result; 130 | var url = formResults.Url; 131 | if (context.Activity.ChannelId == "skype") 132 | { 133 | url = Helpers.ParseAnchorTag(formResults.Url); 134 | } 135 | 136 | await context.GetAccessToken(url); 137 | context.UserData.TryGetValue(ContextConstants.AuthResultKey, out _authResult); 138 | 139 | var returnedItems = SharePointInfo.GetWebProperties(_authResult, url); 140 | 141 | foreach (var answer in returnedItems) 142 | { 143 | var message = answer; 144 | await context.PostAsync(message); 145 | } 146 | var finalMessage = $"What's next?"; 147 | await context.PostAsync(finalMessage); 148 | context.Wait(MessageReceived); 149 | } 150 | 151 | private async Task AfterUrlProvided(IDialogContext context, IAwaitable result) 152 | { 153 | 154 | var formResults = await result; 155 | context.UserData.TryGetValue("ResourceId", out _resourceId); 156 | var tenantUrl = $"https://{_resourceId}-admin.sharepoint.com"; 157 | WebApiApplication.Telemetry.TrackTrace(context.CreateTraceTelemetry(nameof(AfterUrlProvided), new Dictionary { { "Getting admin site:", tenantUrl } })); 158 | await context.GetAccessToken(tenantUrl); 159 | context.UserData.TryGetValue(ContextConstants.AuthResultKey, out _authResult); 160 | var success = Create.CreateSiteColleciton(_authResult, formResults, tenantUrl, _resourceId); 161 | if (success) 162 | { 163 | string message = $"Site Collection creation request send. What's next?"; 164 | await context.PostAsync(message); 165 | } 166 | else 167 | { 168 | WebApiApplication.Telemetry.TrackTrace(context.CreateTraceTelemetry(nameof(AfterUrlProvided), new Dictionary { { "Site Collection creation error:", JsonConvert.SerializeObject(result) } })); 169 | string message = $"Sorry something went wrong. Please try again later."; 170 | await context.PostAsync(message); 171 | } 172 | 173 | context.Wait(MessageReceived); 174 | } 175 | 176 | 177 | } 178 | } -------------------------------------------------------------------------------- /SharePointAdminBot/Global.asax: -------------------------------------------------------------------------------- 1 | <%@ Application Codebehind="Global.asax.cs" Inherits="SharePointAdminBot.WebApiApplication" Language="C#" %> 2 | -------------------------------------------------------------------------------- /SharePointAdminBot/Global.asax.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Linq; 5 | using System.Web; 6 | using System.Web.Http; 7 | using System.Web.Routing; 8 | 9 | namespace SharePointAdminBot 10 | { 11 | public class WebApiApplication : System.Web.HttpApplication 12 | { 13 | public static Microsoft.ApplicationInsights.TelemetryClient Telemetry { get; } = new Microsoft.ApplicationInsights.TelemetryClient(); 14 | protected void Application_Start() 15 | { 16 | Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.Active.InstrumentationKey = ConfigurationManager.AppSettings["iKey"]; 17 | 18 | GlobalConfiguration.Configure(WebApiConfig.Register); 19 | AuthBot.Models.AuthSettings.Mode = ConfigurationManager.AppSettings["ActiveDirectory.Mode"]; 20 | AuthBot.Models.AuthSettings.EndpointUrl = ConfigurationManager.AppSettings["ActiveDirectory.EndpointUrl"]; 21 | AuthBot.Models.AuthSettings.Tenant = ConfigurationManager.AppSettings["ActiveDirectory.Tenant"]; 22 | AuthBot.Models.AuthSettings.RedirectUrl = ConfigurationManager.AppSettings["ActiveDirectory.RedirectUrl"]; 23 | AuthBot.Models.AuthSettings.ClientId = ConfigurationManager.AppSettings["ActiveDirectory.ClientId"]; 24 | AuthBot.Models.AuthSettings.ClientSecret = ConfigurationManager.AppSettings["ActiveDirectory.ClientSecret"]; 25 | 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /SharePointAdminBot/Helpers.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Text.RegularExpressions; 3 | 4 | namespace SharePointAdminBot 5 | { 6 | public static class Helpers 7 | { 8 | 9 | /// 10 | /// Gets the href value in an anchor element. 11 | /// 12 | /// Skype transforms raw urls to html. Here we extract the href value from the url 13 | /// Anchor tag html. 14 | /// True if valid anchor element 15 | public static string ParseAnchorTag(string text) 16 | { 17 | var regex = new Regex("^[^\"]*)\">[^<]*$", RegexOptions.IgnoreCase); 18 | var url = regex.Matches(text).OfType().Select(m => m.Groups["href"].Value).FirstOrDefault(); 19 | return url; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /SharePointAdminBot/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("SharePointAdminBot")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SharePointAdminBot")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 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("a8ba1066-5695-4d71-abb4-65e5a5e0c3d4")] 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 Revision and Build Numbers 33 | // by using the '*' as shown below: 34 | [assembly: AssemblyVersion("1.0.0.1")] 35 | [assembly: AssemblyFileVersion("1.0.0.1")] 36 | -------------------------------------------------------------------------------- /SharePointAdminBot/Service References/Application Insights/ConnectedService.json: -------------------------------------------------------------------------------- 1 | { 2 | "ProviderId": "Microsoft.ApplicationInsights.ConnectedService.ConnectedServiceProvider", 3 | "Version": "7.18.214.2", 4 | "GettingStartedDocument": { 5 | "Uri": "https://go.microsoft.com/fwlink/?LinkID=613413" 6 | } 7 | } -------------------------------------------------------------------------------- /SharePointAdminBot/Web.Debug.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 29 | 30 | -------------------------------------------------------------------------------- /SharePointAdminBot/Web.Release.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 17 | 18 | 19 | 30 | 31 | -------------------------------------------------------------------------------- /SharePointAdminBot/Web.config: -------------------------------------------------------------------------------- 1 |  2 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 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 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | -------------------------------------------------------------------------------- /SharePointAdminBot/default.htm: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | SharePoint Admin Bot 5 | 6 | 7 | 8 |

Welcome to the SharePoint Administration bot

9 |

More information about this bot can be found on the github page GitHub repo

10 |
11 | 12 | 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /SharePointAdminBot/packages.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 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /TermsOfUse.MD: -------------------------------------------------------------------------------- 1 | These terms are an agreement between you and the bot publisher for the use of the bot publisher’s bot on the platform. Please read them. They apply to your use of the bot, including any updates to the bot, unless the bot publisher provides you with separate terms, in which case those terms apply. The bot publisher means the entity making the bot available to you, SPAdminBot. 2 | 3 | IF YOU DO NOT ACCEPT THESE TERMS, YOU HAVE NO RIGHT TO AND MUST NOT USE THE BOT. 4 | 5 | By accepting these terms, you represent that you are at least 18 years old or have reached the age of majority where you live, if that is more than 18 years of age. If you are under 18 or have not reached such age of majority, your parent or legal guardian must accept these terms on your behalf. 6 | 7 | If you comply with these terms, you have the rights below. 8 | 9 | USE: You may use the bot for the sole purpose of interacting with the service provided by the bot publisher on the platform. The bot publisher reserves all other rights. 10 | 11 | RESTRICTIONS: You may not: 12 | 13 | Work around any technical limitations of the bot; 14 | 15 | Modify, reverse engineer or otherwise alter the bot (except to the extent this is authorized by applicable law notwithstanding this limitation); 16 | 17 | Use the bot in any way prohibited by law, regulation, governmental order or decree; 18 | 19 | Use the bot to: 20 | 21 | defame, abuse, harass, stalk, threaten, or otherwise violate the legal rights (such as rights of privacy and publicity) of others; 22 | 23 | engage in activity that is false or misleading or that is harmful to you, others (including children), or the bot (e.g., transmitting viruses, communicating hate speech, or advocating violence against others); 24 | 25 | share inappropriate content, advertising, spam, spyware or malware; 26 | 27 | gain (or attempt to gain) unauthorized access to any service, data, account or network by any means. 28 | 29 | Infringe upon the rights of others; 30 | 31 | Use the bot anywhere other than the platform where the bot publisher has made it available, unless the bot publisher has enabled such uses; 32 | 33 | Remove, modify, or tamper with any notice or link that is incorporated into the bot. 34 | 35 | TERMINATION: If bot publisher believes that you are making unauthorized use of the bot or that you are in violation of these terms, it may suspend or terminate your access to bot publisher’s service with or without notice. This may result in a loss of your data. 36 | 37 | YOUR CONTENT: You grant to bot publisher the right to use any content that you submit via the bot as necessary for bot publisher to provide the service to you. 38 | 39 | TECHNOLOGY AND EXPORT RESTRICTIONS. The bot may be subject to United States or international technology control or export laws and regulations. You must comply with all domestic and international export laws and regulations that apply to the technology used or supported by the bot. 40 | 41 | SUPPORT SERVICES. Contact the bot publisher to determine if any support services are available. 42 | 43 | CHANGES TO TERMS. Bot publisher may update these terms of use at any time by amending this page. Please check this page from time to time to take notice of any changes, as they are binding on you. 44 | 45 | ENTIRE AGREEMENT. This agreement and any applicable privacy policy are the entire agreement between you and the bot publisher. 46 | 47 | APPLICABLE LAW. 48 | 49 | United States and Canada. If you acquired the bot in the United States or Canada, the laws of the state or province where you live (or, if a business, where your principal place of business is located) govern the interpretation of these terms, claims for breach of them, and all other claims (including consumer protection, unfair competition, and tort claims), regardless of conflict of law principles. 50 | 51 | Outside the United States and Canada. If you acquired the bot in any other country, the laws of that country apply. 52 | 53 | LEGAL EFFECT. This agreement describes certain legal rights. You may have other rights under the laws of your state or country. This agreement doesn’t change your rights under the laws of your state or country if the laws of your state or country don’t permit it to do so. 54 | 55 | DISCLAIMER OF WARRANTY. The bot and the service accessed via the bot are provided “as is” “with all faults” and “as available”. You bear the risk as to its quality and performance. The bot publisher gives no express warranties, guarantees, or conditions in relation to the bot. To the extent permitted under your local laws, Bot publisher excludes any implied warranties or conditions, including those of merchantability, fitness for a particular purpose and non-infringement. 56 | 57 | LIMITATION ON AND EXCLUSION OF REMEDIES AND DAMAGES. To the extent not prohibited by law, if you have any basis for recovering damages, you can recover from the bot publisher only direct damages up to the amount you paid for the bot or USD$1.00, whichever is greater. You will not, and waive any right to, seek to recover any other damages, including consequential, lost profits, special, indirect or incidental damages from the bot publisher. If your local laws impose a warranty, guarantee or condition even though these terms do not, its duration is limited to 90 days from when you begin using the bot. 58 | 59 | This limitation applies to: 60 | 61 | Anything related to the bot or services made available through the bot; and 62 | 63 | Claims for breach of contract, warranty, guarantee, or condition; strict liability, negligence, or other tort; violation of a statute or regulation; unjust enrichment; or under any other theory; all to the extent permitted by applicable law. 64 | 65 | This limitation applies even if: 66 | 67 | This remedy doesn’t fully compensate you for any losses; or 68 | 69 | The bot publisher knew or should have known about the possibility of the damages. 70 | --------------------------------------------------------------------------------