API, Box, C#, Certificates, Web, XML

How To Use the Box API To Adjust User Properties and Make Read-Only in Bulk (w/example)

  • Get up to date on the APIs you need for users @ https://developer.box.com/v2.0/reference
  • Sign up for your developer account at your enterprise @ https://yourenterprise.app.box.com/developers/console (replace with your enterprise application name in the link above)
  • Create your Box app & API Key – link here and here
  • Pull down the Box Windows SDK @ – https://github.com/box/box-windows-sdk-v2
  • Update the pem file with your actual pem information from the app you created
    • in case you’re wondering it should contain the —–BEGIN ENCRYPTED PRIVATE KEY—– and —–END ENCRYPTED PRIVATE KEY—–
  • Update the properties appropriately in the app.config
  <appSettings>
    <add key="boxClientId" value="uniquestringhere" />
    <add key="boxClientSecret" value="uniquestringheretoo" />
    <add key="boxEnterpriseId" value="1234567" />
    <add key="boxPrivateKeyPassword" value="uniquestringhereforpassword" />
    <add key="boxPublicKeyId" value="uniquepublickeyid" />
    <add key="ClientSettingsProvider.ServiceUri" value="useifneeded" />
  </appSettings>
  • From there you can update your Main runner in the program.cs appropriately. In the case of my sample below I am getting authorized, retrieving my users and looping through everyone but the main admin account and making them read-only. I’m also writing the information out to a file so I’ll have the logs of who was set / not set.
 
            var privateKey = File.ReadAllText("private_key.pem");

            var boxConfig = new BoxConfig(CLIENT_ID, CLIENT_SECRET, ENTERPRISE_ID, privateKey, JWT_PRIVATE_KEY_PASSWORD, JWT_PUBLIC_KEY_ID);
            var boxJWT = new BoxJWTAuth(boxConfig);

            var adminToken = boxJWT.AdminToken();
            Console.WriteLine("Admin Token: " + adminToken);
            Console.WriteLine();

            var adminClient = boxJWT.AdminClient(adminToken);

            var items = await adminClient.UsersManager.GetEnterpriseUsersAsync("", 0, 1000);
            items.Entries.ForEach(async i =>
            {
                if (i.Login != "myspecialadminaccount@domain.com")
                {
                    BoxUserRequest userRequest = new BoxUserRequest()
                    {
                        Id = i.Id,
                        Status = "cannot_delete_edit_upload"
                    };
                    System.Console.WriteLine("\t{0}", i.Name);
                    System.Console.WriteLine("\t{0}", i.Id);
                    System.Console.WriteLine("\t{0}", i.Login);
                    System.Console.WriteLine("\t{0}", i.Type);
                    System.Console.WriteLine(" ");
                    // Turn on for prod
                    BoxUser user = await adminClient.UsersManager.UpdateUserInformationAsync(userRequest);
                    Console.WriteLine(userRequest.Name + "updated to read-only");
                    System.Threading.Thread.Sleep(2000);
                    stringtext = i.Name.ToString() + " - " + i.Id.ToString() + " - " + i.Login.ToString() + " - " + i.Type.ToString() + " - updated to readonly" + Environment.NewLine;
                    System.Console.WriteLine(" ");
                    
                }
                else
                {
                    BoxUserRequest userRequest = new BoxUserRequest()
                    {
                        Id = i.Id
                    };
                    System.Console.WriteLine("\t{0}", i.Name);
                    System.Console.WriteLine("\t{0}", i.Id);
                    System.Console.WriteLine("\t{0}", i.Login);
                    System.Console.WriteLine("\t{0}", i.Type);
                    System.Console.WriteLine(" ");
                    Console.WriteLine(userRequest.Name + " NOT updated to read-only");
                    System.Threading.Thread.Sleep(2000);
                    stringtext = i.Name.ToString() + " - " + i.Id.ToString() + " - " + i.Login.ToString() + " - " + i.Type.ToString() + " - NOT updated to readonly" + Environment.NewLine;
                    System.Console.WriteLine(" ");
                    
                }
            });
            File.AppendAllText("C:\\Temp\\" + "log.txt", stringtext);
  • Enable your box application to your enterprise accounts – link here
  • Run your app (In TEST with test accounts! Then, with approval, prod.)
    • If the app won’t run…check:
      • code syntax errors
      • certificate pem
      • values in the app config
      • authorization status in the admin Console on Box
      • that your app is enabled and still available on the enterprise developer site

Hope this helps! I can send the source out on request if needed (just let me know).

.Net, HTML, IIS, Sitecore, Visual Studio, Web, XML

Sitecore Error (SOLVED): An item name cannot contain any of the following characters: \/:?”\-|[] (controlled by the setting InvalidItemNameChars)

You may have ran into an issue during deployments when trying to publish in the past where you have seen this message:

“An item name cannot contain any of the following characters: \/:?”<>\-|[] (controlled by the setting InvalidItemNameChars)”

In order to help move forward on this you need to disable the default ItemNameValidation settings if you are having some deployment issues.

To do that (would only recommend temporarily) you can follow the steps below:

Add a config file to App_Config/Include named z.DisableItemNameValidation.config and put this in it:

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/">
  <sitecore>
    <settings>
      <setting name="ItemNameValidation">
        <patch:attribute name="value"></patch:attribute>
      </setting>
    </settings>
  </sitecore>
</configuration>

Again, when you are finished I would recommend taking this back out of your files to keep things as standard as possible.

.Net, AWS, C#, IIS, Programming, Web, XML

Ready to send email in Amazon SES? Let’s Go!

First, consult with AWS and get your credentials:

http://docs.aws.amazon.com/ses/latest/DeveloperGuide/using-credentials.html
and
http://docs.aws.amazon.com/ses/latest/DeveloperGuide/send-using-smtp-net.html

Secondly, let’s make a more easily updatable emailSettings section (encrypt it later, see here if you need help):

  <appSettings>
    <add key="MailFrom" value="donotreply@youremaildomain.com"/>
    <add key="MailTo" value="whoareyousendingto@theiremaildomain.com"/>
    <add key="MailHost" value="	email-smtp.youramazonseshost.com"/>
    <add key="MailPort" value="587"/>
    <add key="MailServerUserName" value="awsSESusername"/>
    <add key="MailServerPassword" value="awsSESpassword"/>
  </appSettings>

Then, include the reference:

	using System.Net.Mail;		

Finally, write your method:

	public static void sendEmail(string to, string from, string subject, string body)
	{
		try
		{
			// Initialize client and message
			using (SmtpClient mailclient = new SmtpClient(ConfigurationManager.AppSettings["MailHost"].ToString(), Convert.ToInt32(ConfigurationManager.AppSettings["MailPort"])))
			{
				// Create message
				mailclient.UseDefaultCredentials = false;
				mailclient.EnableSsl = true;
				mailclient.Credentials = new System.Net.NetworkCredential(ConfigurationManager.AppSettings["MailServerUserName"].ToString(), ConfigurationManager.AppSettings["MailServerPassword"].ToString());
				MailMessage message = new MailMessage(from, to);
				message.Subject = subject;
				message.Body = body;
				message.IsBodyHtml = true;
				mailclient.Send(message);
			}
		}
		catch (SmtpException ex)
		{                
			// Service was not available to send message keep trying
			if (ex.StatusCode.Equals(SmtpStatusCode.ServiceNotAvailable))
			{
				sendEmail(to, from, subject, body);
			}
		}
	}

Great! Now you can call it and send an email

string htmlBody = "<b>Hi! It's my message</b>";
sendEmail(ConfigurationManager.AppSettings["MailTo"].ToString(), ConfigurationManager.AppSettings["MailFrom"].ToString(), "Your Email Subject", htmlBody); 

You can always put whoever and whatever when you call the method using To, From, Subject and Body.

Enjoy! Questions are welcome.

.Net, IIS, Programming, Troubleshooting, Visual Studio, Web, XML

Troubleshooting “Could not load file or assembly ‘DotNetOpenAuth.Core, Version=4.1.0.0, Culture=neutral, PublicKeyToken=2780ccd10d57b246’ or one of its dependencies”

The Issue:

After I had updated my .Net Core on my developer machine to a newer version I went to debug a web application I had and received this error:

Could not load file or assembly 'DotNetOpenAuth.Core, Version=4.1.0.0, Culture=neutral, PublicKeyToken=2780ccd10d57b246' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

The Problem:

Here is what I had in my config prior to the update install:

<runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="DotNetOpenAuth.Core" publicKeyToken="2780ccd10d57b246" />
        <bindingRedirect oldVersion="1.0.0.0-4.0.0.0" newVersion="4.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="DotNetOpenAuth.AspNet" publicKeyToken="2780ccd10d57b246" />
        <bindingRedirect oldVersion="1.0.0.0-4.0.0.0" newVersion="4.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="EntityFramework" publicKeyToken="b77a5c561934e089" />
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

I had outdated references in my config file.

The Solution:

Ensure your references get updated after you update your development environment.

Here is what I updated to:

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="DotNetOpenAuth.AspNet" publicKeyToken="2780ccd10d57b246" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="DotNetOpenAuth.Core" publicKeyToken="2780ccd10d57b246" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="EntityFramework" publicKeyToken="b77a5c561934e089" />
        <bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

Hope that helps. Questions are always welcome.

.Net, IIS, Security, Sitecore, Web, XML

Encrypting .NET Config Files in a Shared Development Environment

This page will attempt to describe how to encrypt sensitive information contained in .NET config files using the RSA Key Container, as well as how to export/import the key from that container so that other developers may use the same key to work on the same project.

Helpful Tips: The aspnet_regiis.exe utility must be run as a administrator, otherwise you may receive “duplicate object” errors. In addition, you will want to run Visual Studio as an administrator to ensure the program has access to the RSA Key Container store.

Creating a Custom RSA Key Container

In this part we will create an RSA key container by using aspnet_regiis.exe with the -pc option. This identifies the RSA key container as a user-level key container. RSA key containers must be identified as either user-level (by using the -pku option) or machine-level (by not using the -pku option). For more information about machine-level and user-level RSA key containers, see Understanding Machine-Level and User-Level RSA Key Containers.

In this example the following command will create an RSA key container named SampleKeys that is a machine-level key container and is exportable:

cd \WINDOWS\Microsoft.Net\Framework\v4.0.*
aspnet_regiis -pc "SampleKeys"–exp

Adding your provider to the web.config

The following example shows the configProtectedData section of a Web.config file. The section specifies an RsaProtectedConfigurationProvider that uses a machine-level RSA key container named SampleKeys.

<configProtectedData>
   <providers>
    <add keyContainerName="SampleKeys" useMachineContainer="true" description="RsaCryptoServiceProvider" name="SampleKeys" type="System.Configuration.RsaProtectedConfigurationProvider,System.Configuration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
   </providers>
</configProtectedData>

Importing and Exporting the Key Container

In order for another developer to run your project (encrypted by your key) you will need to  export a key to be used by another developer:

aspnet_regiis -px "SampleKeys" "C:\keys.xml" -pri

Once you pass this along to another user to use then import with the following command:

aspnet_regiis -pi "SampleKeys" "C:\keys.xml"

If this is a machine level container, the code should now run without the need to assign permissions. However, if it’s a user container (i.e. your app pool is ran by a specific user or service account), additional permissions may need to be assigned:

aspnet_regiis -pa "SampleKeys" "NT AUTHORITY\NETWORK SERVICE"
aspnet_regiis -pa "SampleKeys" "[impersonation account]"

To use the default RsaProtectedConfigurationProvider specified in the machine configuration, you must first grant the application’s Windows identity access to the machine key container named NetFrameworkConfigurationKey, which is the key container specified for the default provider. For example, the following command grants the NETWORK SERVICE account access to the RSA key container used by the default RsaProtectedConfigurationProvider:

aspnet_regiis -pa "NetFrameworkConfigurationKey" "NT AUTHORITY\NETWORK SERVICE"

Encrypting and Decrypting Config Sections

.NET allows specific sections of a config file to be encrypted, so non-sensitive information can still be accessed. To encrypt a section:

aspnet_regiis -pef [section] [path] -prov [provider]

Where [section] is the name of the config section, relative to the configuration tag. [path] is the relative path to the directory containing the web.config file. For example, the following commands will encrypt the appSettings section as well as the impersonation credentials:

cd C:\SolutionFolder
aspnet_regiis -pef appSettings ProjectFolder -prov SampleKeys
aspnet_regiis -pef system.web/identity ProjectFolder -prov SampleKeys

To decrypt the appSettings section:

aspnet_regiis -pdf appSettings ProjectFolder

Partially Encrypting a Section

It may be necessary to only encrypt part of a section in a web.config file. For example, if the appSettings section contains multiple, non-sensitive keys and only a subset contain sensitive information. To encrypt only a few keys, a second appSettings section must be created and the new keys moved into it. The keys are accessed exactly the same way in the code, so no coding changes are needed.

First, register a new section name called secureAppSettings by placing the following XML under the configuration node:

<configSections>
<section name="secureAppSettings" type="System.Configuration.NameValueSectionHandler, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</configSections>

Next, create a new section called secureAppSettings and move the sensitive keys under it:

<secureAppSettings>
    <add key="Username" value="XXX" />
    <add key="Password" value="XXX" />
</secureAppSettings>
<appSettings>
    <add key="NotSensitive" value="XXX" />
</appSettings>

Finally, the new secure section can be encrypted and decrypted independently of the existing appSettings section:

aspnet_regiis -pef secureAppSettings ProjectFolder -prov ProviderName

App.config

This Microsoft utility was designed for web.config files. It will not find app.config files for other project types. To encrypt these config files, just rename them to web.config prior to encrypting, then rename back afterwards.

Other Helpful Links: