Posts Tagged ‘ASP.NET’

OAuth 2.0 with Gmail over IMAP for web applications

Monday, March 13th, 2017

OAuth is an open protocol to allow secure API authorization in a simple and standard method from desktop and web applications.

This article describes using OAuth 2.0 to access Gmail IMAP and SMTP servers using .NET IMAP component in web application scenario (ASP.NET/ASP.NET MVC). You can also use OAuth 2.0 for installed applications.

Google.Apis

Use Nuget to download “Google.Apis.Auth” package.

Import namespaces:

// c#

using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Flows;
using Google.Apis.Auth.OAuth2.Requests;
using Google.Apis.Auth.OAuth2.Responses;

using Limilabs.Client.Authentication.Google;

using Limilabs.Client.IMAP;
' VB.NET 

Imports Google.Apis.Auth.OAuth2
Imports Google.Apis.Auth.OAuth2.Flows
Imports Google.Apis.Auth.OAuth2.Requests
Imports Google.Apis.Auth.OAuth2.Responses

Imports Limilabs.Client.Authentication.Google

Imports Limilabs.Client.IMAP

Register Application

Before you can use OAuth 2.0, you must register your application using the Google Developers Console. After you’ve registered, go to the API Access tab and copy the “Client ID” and “Client secret” values and specify “Redirect URI“, which you’ll need later.

At least product name must be specified:

Now create credentials:

Specify redirect URI:

After you’ve registered, copy the “Client ID” and “Client secret” values, which you’ll need later:

Now we can define clientID, clientSecret, redirect url and scope variables, as well as Google OAuth 2.0 server addresses. Scope basically specifies what services we want to have access to. In our case it is user’s email address and IMAP/SMTP access:

// c#

string clientID = "XXX.apps.googleusercontent.com";
string clientSecret = "IxBs0g5sdaSDUz4Ea7Ix-Ua";
string redirectUri = "http://www.yourdomain.com/oauth2callback";

var clientSecrets = new ClientSecrets
{
    ClientId = clientID,
    ClientSecret = clientSecret
};

var credential = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
    ClientSecrets = clientSecrets,
    Scopes = new[] { GoogleScope.ImapAndSmtp.Name, GoogleScope.EmailScope.Name}
});
' VB.NET 

Dim clientID As String = "XXX.apps.googleusercontent.com"
Dim clientSecret As String = "IxBs0g5sdaSDUz4Ea7Ix-Ua"
Dim redirectUri As String = "http://www.yourdomain.com/oauth2callback"

Dim clientSecrets = New ClientSecrets() With { _
	Key .ClientId = clientID, _
	Key .ClientSecret = clientSecret _
}

Dim credential = New GoogleAuthorizationCodeFlow(New GoogleAuthorizationCodeFlow.Initializer() With { _
	Key .ClientSecrets = clientSecrets, _
	Key .Scopes = New () {GoogleScope.ImapAndSmtp.Name, GoogleScope.EmailScope.Name} _
})

Turn on Google+ API

Remember to turn on Google+ API:
Turn on Google+ API

It is required to obtain email address of the user.

Obtain an OAuth 2.0 access token

Now we’ll create authorization url:


AuthorizationCodeRequestUrl url = credential.CreateAuthorizationCodeRequest(redirectUri);

' VB.NET 

Dim url As AuthorizationCodeRequestUrl = credential.CreateAuthorizationCodeRequest(redirectUri)

Now we need to redirect the client:

// c#

return new RedirectResult(url.Build().ToString());

' VB.NET 

Return New RedirectResult(url.Build().ToString())

At this point user is redirected to Google to authorize the access:

After this step user is redirected back to your website (http://www.yourdomain.com/oauth2callback), with code request parameter:
http://www.yourdomain.com/oauth2callback?code=4/5Y7M4cARD9hrt0nuKnQa0YgtYMasdbwprRtIIjk4Fus#

// c#

public class OAauth2CallbackController : Controller
{
    public ActionResult Index(string code)
    {
        ...
    }
}
' VB.NET 

Public Class OAauth2CallbackController
    Inherits Controller
    Public Function Index(code As String) As ActionResult
        ...
    End Function
End Class

Following is this callback code. Its purpose is to get a refresh-token and an access-token:

// c#

string authCode = code;

TokenResponse token = await credential.ExchangeCodeForTokenAsync("", authCode, redirectUri, CancellationToken.None);

string accessToken = token.AccessToken;
' VB.NET 

Dim authCode As String = code

Dim token As TokenResponse = Await credential.ExchangeCodeForTokenAsync("", authCode, redirectUri, CancellationToken.None)

Dim accessToken As String = token.AccessToken

An access token is usually valid for a maximum of one hour, and allows you to access the user’s data. You also received a refresh token. A refresh token can be used to request a new access token once the previous expired.

Access IMAP/SMTP server

Finally we’ll ask Google for user’s email and use LoginOAUTH2 method to access Gmail’s IMAP server:

// c#

GoogleApi api = new GoogleApi(accessToken);
string user = api.GetEmailPlus();

using (Imap imap = new Imap())
{
    imap.ConnectSSL("imap.gmail.com");
    imap.LoginOAUTH2(user, accessToken);

    imap.SelectInbox();
    List<long> uids = imap.Search(Flag.Unseen);

    foreach (long uid in uids)
    {
        var eml = imap.GetMessageByUID(uid);
        IMail email = new MailBuilder().CreateFromEml(eml);
        Console.WriteLine(email.Subject);
    }
    imap.Close();
}
' VB.NET 

Dim api As New GoogleApi(accessToken)
Dim user As String = api.GetEmailPlus()

Using imap As New Imap()
	imap.ConnectSSL("imap.gmail.com")
	imap.LoginOAUTH2(user, accessToken)

	imap.SelectInbox()
	Dim uids As List(Of Long) = imap.Search(Flag.Unseen)

	For Each uid As Long In uids
		Dim eml = imap.GetMessageByUID(uid)
		Dim email As IMail = New MailBuilder().CreateFromEml(eml)
		Console.WriteLine(email.Subject)
	Next
	imap.Close()
End Using

Refreshing access token

An access token is usually short lived and valid for a maximum of one hour. The main reason behind this is security and prevention of replay attacks. This means that for long-lived applications you need to refresh the access token.

Your refresh token will be sent only once – don’t loose it!

We recommend storing entire TokenResponse object received from GoogleAuthorizationCodeFlow.ExchangeCodeForTokenAsync method call. This object contains both: refresh token and access token, along with its expiration time.

The process of refreshing access token is simple:

// c#

TokenResponse refreshed = await credential.RefreshTokenAsync("", token.RefreshToken, CancellationToken.None);

' VB.NET 

Dim refreshed As TokenResponse = Await credential.RefreshTokenAsync("", token.RefreshToken, CancellationToken.None)

OAuth 2.0 with Outlook.com over IMAP for web applications

Saturday, September 14th, 2013
You can also read how to use:

Outlook

OAuth is an open protocol to allow secure API authorization in a simple and standard method from desktop and web applications.

This article describes using OAuth 2.0 to access Outlook.com IMAP and SMTP servers using .NET IMAP component in web application scenario (ASP.NET/ASP.NET MVC). You can also use OAuth 2.0 with Outlook.com for installed/native applications.

DotNetOpenAuth

First download the latest version of DotNetOpenAuth – it’s free, open source library that implements OAuth 2.0: http://www.dotnetopenauth.net

Add it as a reference and import namespaces:

// c#

using DotNetOpenAuth.OAuth2;
' VB.NET 

Imports DotNetOpenAuth.OAuth2

Register Application

Before you can use OAuth 2.0, you must register your application using the application management site. After you’ve registered, go to the My applications and create new application. On “API Settings” page, copy “Client ID” and “Client secret” values and specify “Redirect domain“, which you’ll need later.

Outlook_AddAppKeys

Redirect domain must be valid domain address. You can’t use localhost, which is problematic during development phase. For testing purposes you can use fake domain. You just need to modify your computer’s hosts file (c:\Windows\System32\drivers\etc\hosts) so it redirects to localhost:
127.0.0.1 fake-domain-9065436322.com

Now we can define clientID, clientSecret, redirect url and scope variables, as well as Outlook.com OAuth 2.0 server addresses. Scope basically specifies what services we want to have access to. In our case it is user’s email address and IMAP/SMTP access:

string clientID = "000000014810009D";
string clientSecret = "wiRCccXnq1uyKcXnq1uyK";
string redirectUri = "http://fake-domain-9650932456.com/OAuth2.aspx";

AuthorizationServerDescription server = new AuthorizationServerDescription
{
    AuthorizationEndpoint = new Uri("https://login.live.com/oauth20_authorize.srf"),
    TokenEndpoint = new Uri("https://login.live.com/oauth20_token.srf"),
    ProtocolVersion = ProtocolVersion.V20,
};

List<string> scope = new List<string> 
    { 
        OutlookScope.ImapAndSmtp.Name, 
        OutlookScope.EmailAddress.Name 
    };

Obtain an OAuth 2.0 access token

As we are using ASP.NET we’ll use WebServerClient class:

WebServerClient consumer = new WebServerClient(server, clientID, clientSecret);

// Here redirect to authorization site occurs
consumer.RequestUserAuthorization(scope, new Uri(redirectUri));

If you use ASP.NET MVC the last line is different:

// Here redirect to authorization site occurs
OutgoingWebResponse response = consumer.PrepareRequestUserAuthorization(
    scope, new Uri(redirectUri));
return response.AsActionResult();

At this point user is redirected to Microsoft to authorize the access:

Outlook_2Confirm

After this step user is redirected back to your website (http://fake-domain-9650932456.com/OAuth2.aspx). Following is this callback code. Its purpose is to get a refresh-token and an access-token:

WebServerClient consumer = new WebServerClient(server, clientID, clientSecret);
IAuthorizationState grantedAccess = consumer.ProcessUserAuthorization(null);

string accessToken = grantedAccess.AccessToken;

An access token is usually short lived, and allows you to access the user’s data. You also received a refresh token. A refresh token can be used to request a new access token once the previous expired.

Access IMAP/SMTP server

Finally we’ll ask Microsoft for user’s email and use LoginOAUTH2 method to access Outlook.com IMAP server:

OutlookApi api = new OutlookApi(accessToken);
string user = api.GetEmail();

using (Imap imap = new Imap())
{
    imap.ConnectSSL("imap-mail.outlook.com");
    imap.LoginOAUTH2(user, accessToken);

    imap.SelectInbox();
    List<long> uids = imap.Search(Flag.Unseen);

    foreach (long uid in uids)
    {
        var eml = imap.GetMessageByUID(uid);
        IMail email = new MailBuilder().CreateFromEml(eml);
        Console.WriteLine(email.Subject);
    }
    imap.Close();
}

Refreshing access token

An access token is usually short lived. The main reason behind this is security and prevention of replay attacks. This means that for long-lived applications you need to refresh the access token.

In most cases web applications don’t need to refresh access token (they request new one every time), thus when using WebServerClient refresh token is not sent. To force sending refresh token you need to add “wl.offline_access” to requested scopes:


List<string> scope = new List<string> 
    { 
        OutlookScope.ImapAndSmtp.Name, 
        OutlookScope.EmailAddress.Name, 
        OutlookScope.OfflineAccess.Name 
    };

Your refresh token will be sent only once – don’t loose it!

We recommend storing entire IAuthorizationState object received from WebServerClient.ProcessUserAuthorization method call. This object contains both: refresh token and access token, along with its expiration time.

The process of refreshing access token is simple:

IAuthorizationState grantedAccess = ...
consumer.RefreshAuthorization(grantedAccess, TimeSpan.FromMinutes(20));

In the example above the access token will not be refreshed if its remaining lifetime exceeds 20 minutes.

Apps and services you’ve given access

Users can manage consent for applications and services that can access some of their data on consent panel

Get IIS pickup directory location

Thursday, August 22nd, 2013

If you plan to use local IIS SMTP service to send emails you created using Mail.dll, you’ll need to save those emails to IIS pickup folder.

Default folder location is “c:\Inetpub\mailroot\Pickup”

There is a way to get IIS pickup folder location directly from IIS metabase. To get this path programmatically we’ll use IisPickupDirectory class. Unfortunatelly this class is not public, we’ll use its name to get its type and Activator class to invoke private static method GetPickupDirectory.

To get type reference, we need to specify fully qualified type name “System.Net.Mail.IisPickupDirectory System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”. We can also search CurrentDomain’s assemblies to find System assembly and get its full name.

Assembly system = AppDomain.CurrentDomain.GetAssemblies()
    .First(x => x.GetName().Name == "System");

Type iisPickupType = Type.GetType(
    "System.Net.Mail.IisPickupDirectory, "
    + system.GetName().FullName,
    true);
// -or- use fully qualified assembly name directly:
//Type iisPickupType = Type.GetType(
//    "System.Net.Mail.IisPickupDirectory, "
//    + "System, Version=4.0.0.0, Culture=neutral, " 
//    + "PublicKeyToken=b77a5c561934e089",
//    true);

string pickupFolder = (string)iisPickupType.InvokeMember(
    "GetPickupDirectory",
    BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.NonPublic,
    null, null, null);

“Cannot get IIS pickup directory.” error

Unfortunately, this exception is raised when any kind of problem occurs, while trying to determine the location of IIS/SMTP pickup directory.

A common cause is simply missing IIS SMTP service.

The pickup directory is stored in the IIS Metabase, so if the account that your web-app runs as does not have access to the required nodes, this error can be thrown. Metabase permissions are separate from file permissions, so you explore it with Metabase explorer (part of the IIS resource kit).

These nodes need to have read permission given to your web-app user: \LM, \LM\Smtpsrv\ and \LM\Smtpsrv\1

Read system.net/mailSettings/smtp settings from web.config

Sunday, August 18th, 2013

There is a standard way of specifying SMTP settings in .NET applications. .NET uses config files (app.config or web.config in case of ASP.NET) and element to specify the appropriate SMTP parameters to send e-mail.

Sample configuration (in this case Gmail SMTP settings) looks as follows:

<configuration>

<system.net>
  <mailSettings>
    <smtp deliveryMethod="network" from="pam@gmail.com">
      <network
        host="smtp.gmail.com"
        port="465"
        enableSsl="true"
        userName="pam@gmail.com"
        password="password"
    />
    </smtp>
  </mailSettings>
</system.net>

</configuration>

If port attribute is omitted default value (25) is used. SMTP protocol typically uses ports 587 and 25 for non SSL connections, and port 465 for SSL ones.

Although Mail.dll SMTP component does not support reading from web.config directly, it is quite easy to read those settings programmatically and use them with Mail.dll classes.

Here’s the simple sample that reads from mailSettings section:

SmtpSection section = (SmtpSection)ConfigurationManager.GetSection("system.net/mailSettings/smtp");

string from = section.From;
string host = section.Network.Host;
int port = section.Network.Port;
bool enableSsl = section.Network.EnableSsl;
string user = section.Network.UserName;
string password = section.Network.Password;

Use web.config’s mailSettings with Mail.dll

In most cases you want to send email via SMTP server (DeliveryMethod set to SmtpDeliveryMethod.Network). Here’s the sample that uses web.config settings and Mail.dll’s STMP component to send an email message:

SmtpSection section = (SmtpSection)ConfigurationManager.GetSection("system.net/mailSettings/smtp");

IMail email = Fluent.Mail
            .Text("Hi, how are you?")
            .Subject("Hello")
            .To("to@example.com")
            .From(section.From)
            .Create();

using (Smtp client = new Smtp())
{
    client.Connect(section.Network.Host, section.Network.Port, 
        section.Network.EnableSsl);
    client.UseBestLogin(section.Network.UserName, section.Network.Password);
    client.SendMessage(email);
    client.Close();
}

IIS pickup folder

If you plan to use local IIS SMTP service to send emails you created using Mail.dll, you’ll need to save those emails to IIS pickup folder.

You can specify folder location explicitly using SpecifiedPickupDirectory.PickupDirectoryLocation (default location is “c:\Inetpub\mailroot\Pickup”). You can also use SmtpDeliveryMethod.PickupDirectoryFromIis constant – in this case we’ll get pickup folder location directly from IIS metabase.

Following is the code that recognizes different DeliveryMethods and acts accordingly:

SmtpSection section = (SmtpSection)ConfigurationManager.GetSection("system.net/mailSettings/smtp");
IMail email = Fluent.Mail
            .Text("Hi, how are you?")
            .Subject("Hello")
            .To("lesnikowski@limilabs.com")
            .From(section.From)
            .Create();

if (section.DeliveryMethod == SmtpDeliveryMethod.Network)
{
    using (Smtp client = new Smtp())
    {
        client.Connect(section.Network.Host, section.Network.Port, 
            section.Network.EnableSsl);
        client.UseBestLogin(section.Network.UserName, section.Network.Password);
        client.SendMessage(email);
        client.Close();
    }
}
else if (section.DeliveryMethod == SmtpDeliveryMethod.SpecifiedPickupDirectory)
{
    string pickupFolder = section.SpecifiedPickupDirectory.PickupDirectoryLocation;
    email.Save(Path.Combine(pickupFolder, "email.eml"));
}
else if (section.DeliveryMethod == SmtpDeliveryMethod.PickupDirectoryFromIis)
{
    Assembly system = AppDomain.CurrentDomain.GetAssemblies()
        .First(x => x.GetName().Name == "System");
    
    Type iisPickupType = Type.GetType(
        "System.Net.Mail.IisPickupDirectory, " 
        + system.GetName().FullName, 
        true);
    // -or- use fully qualified system assembly name directly:
    //Type iisPickupType = Type.GetType(
    //    "System.Net.Mail.IisPickupDirectory, " 
    //    + "System, Version=4.0.0.0, Culture=neutral, "
    //    + "PublicKeyToken=b77a5c561934e089",
    //    true);

    string pickupFolder = (string)iisPickupType.InvokeMember(
        "GetPickupDirectory", 
        BindingFlags.InvokeMethod | BindingFlags.Static | BindingFlags.NonPublic, 
        null, null, null);

    email.Save(Path.Combine(pickupFolder, "email.eml"));
}

Create barcode in ASP.NET video

Wednesday, February 1st, 2012

In this video you’ll learn how to:

  • Download and install Barcode.dll barcode ASP.NET component.
  • Create new ASP.NET application that references Barcode.dll barcode ASP.NET component.
  • Configure barcode ASP.NET handler.
  • Darg & drop barcode web control.
  • Configure barcode web control.
  • Program barcode control through code.

Enjoy: