Upgrading to BlogEngine.Net 1.4
This weekend I spent sometime upgrading my site to 1.4 version of BlogEngine.Net from 1.3. Following this post from Al Nyveldt, I upgraded the site first on my laptop and tested for proper working then uploaded to the server. But it was not all hunky dory. Major changes have been made which needed to be adapted to, for example, the new themes support the widget model and all my customizations to previous theme had to be redone to take advantage of the new model. It is not to say that the previous theme was not working, it was, but it was static ofcourse as opposed to the new version. Also one control that I had added to it could not put into the new version because its simply a web control and not made to fit the widget model. I might have to do and upgrade on that as well during the week. Another thing that is giving me unnecessary trouble is that editor for the profile widget. It for some reason always points to the /admin folder and does not allow me to refer images from other folders. To bypass that I had to use the relative path ".." trick to move one level up and point the image to some other location.
One thing that has disappointed me is that there is still the lack of good reporting in the engine. I have used Wordpress before and coming from there I consider this a major shortcoming. There is no reporting on the post visits and because of that no controls for popular posts or regular commenter etc. I hope these features are coming soon. But then, this is also an opportunity for those who need it to build these controls for the community.
C# 4.0, what's to come?
I came across this interesting video called "meet the design team" for C# 4.0. After the successful launch of C# 3.0 the design team is already on its way to build the next generation of the language and set the agenda for what is required of it. From the discussion the salient points I can gather are:
Power of dynamic: You know the thing about languages like javascript and VB that you don't have to define everything before hand, like in statically typed languages like C# and its predecessors and you program and define as you go along. Well, the that is the power of dynamic languages. They don't enforce a whole lot of structure on you when writing your programs because they don't care about the program being perfectly typed and thoroughly structured, rather their focus is on the program flow so that you can achieve what you plan to do in the least amount of time. Simple.
Power of functional: If you have worked with any "declarative" language and chances are that you have, then you would know what power functional languages give you. Every developer these days has worked with SQL which is a declarative language and and C# programmers have been exposed to the new LINQ model which is also pretty declarative. The thing about declarative is that instead of writing the program as a series of steps, like a flowchart, where you convert your intent into a well defined structure, you just go ahead and express your intent and say be and it is. Like for example when writing and SQL statement you don't specify "how" it will execute and use indexes and generate temporary tables or loop through a table for every matching row, you just say it should do all that and it does.
Power of concurrency: A point that Anders makes towards the end of the session referring to the Moore's Law, which states that computing power will double every eighteen months, is that the increase of power has taken a shift from more megahertz to more processors because we have kind of reached a limit for how small and fast can we make a processor. So, we are just putting in more of them to meet the demand. Now to effectively adapt to this new trend the languages must have some constructs that allow the programmer to express his "intent" regarding concurrency.
Watch and enjoy.
C# 4.0: Meet the Design Team
Using AD membership provider in ASP.Net
Recently I needed to provide authentication from the Active Directory for a custom ASP.Net form. I was pleasantly surprised to find that there is a ready-made authentication provider available for active directory, similar to the database one.
Despite the provider the second problem was that I had to put the authentication inside a custom form where I could not use the Login controls that are integrated with the membership providers for ASP.Net. Then with little investigation I found out that it was very simple to do that as well and all the functionality of the provider could be accessed from outside the controls. I became a fan of ASP.Net once again.
The steps to use it in the custom form are very simple. Since this is forms authentication, you put in the relevant entry in web.config.
<authentication mode="Forms">
<forms
name=".ADAuthCookie"
timeout="10" />
</authentication>
This put ASP.Net in forms authentication mode, hence next step is to define the details of which forms will be used for this purpose.
<forms name=".ASPXAUTH" loginUrl="login.aspx"
defaultUrl="default.aspx" protection="All" timeout="30" path="/"
requireSSL="false" slidingExpiration="true"
cookieless="UseDeviceProfile" domain=""
enableCrossAppRedirects="false">
<credentials passwordFormat="SHA1" />
</forms>
The above tag specifies the default.aspx page as the url it gets redirected to once the user is authenticated. The authentication is actually done on the login.aspx page. The rest of the parameters define what will be the behavior of the authentication mode, for example, that there will be a 30min timeout with sliding window, it will not use SSL and cookie creation will depend on the client device.
The next step is to secure all the files so that only a select few are available without authentication and the rest can be accessed only after the user has successfully logged in. The few available anonymously contains the login page.
<authorization>
<deny users="?" />
<allow users="*" />
</authorization>
The above tags say that all anonymous accesses should be denied and all authenticated access allowed. The reason for saying both of them is that you can choose what to deny and what to allow. For example you can deny all then allow a selected number of files and directories. This kind of rule logic is common in firewall configurations.
Since we are authenticating through AD, we need to define it as a data source. This data source will first of all have a connection string.
<connectionStrings>
<add name="ADConnectionString" connectionString="LDAP://testdomain.test.com/DC=testdomain,DC=test,DC=com" />
</connectionStrings>
The only thing that needs explanation here is the connectionstring parameter. It is defining that AD will be accessed through LDAP protocol and what follows the // is the server name holding AD, you don't necessarily need to specify the actual server name if the domain name resolves to it. The DC part specifies the domain name. So if its contoso.com then it will be DC=contoso, DC=com. The reason I understand for this is that AD is a hierarchical database and hence we are defining this part of the connection string in a tree fashion. After the connection string we need to define the actual membership provider that will service all authentication queries.
<membership defaultProvider="MyADMembershipProvider">
<providers>
<add
name="MyADMembershipProvider"
type="System.Web.Security.ActiveDirectoryMembershipProvider, System.Web, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="ADConnectionString"
connectionUsername="testdomain\administrator"
connectionPassword="password" attributeMapUsername="sAMAccountName" />
</providers>
</membership>
It references the assembly required and provide a username/password that will be used to query the active directory server. This user should have enough rights to read the active directory. The last attribute attributeMapUsername is set to "sAMAccountName" which means the user will provide username in the format domain\username. While if this was not set then the default format is username@domain. This is all there is to it for the setup. Now lets use it in the code.
The first thing I intend to do is to validate a user from active directory using the submitted username and password. Once the user is authenticated we would typically like to redirect user to the first page, which in our case is defined as the default page in forms configuration.
if (Membership.ValidateUser(username, password))
{
//valid user do your thing here
FormsAuthentication.RedirectFromLoginPage(username, false);
}
else
{
//failed, give some message
}
After authentication from the membership provider we can use the FormsAuthentication class to send the user to the default page. The second parameter which is 'false' in our case relates to the 'Remember Me' in the login box, which allows you to put a persistent cookie.
The followingMSDN article gives you some recommendations on making your website more secure:
Security Considerations
Failing to protect authentication tickets is a common vulnerability that can lead to unauthorized spoofing and impersonation, session hijacking, and elevation of privilege. When you use forms authentication, consider the following recommendations to help ensure a secure authentication approach:
- Restrict the authentication cookie to HTTPS connections. To prevent forms authentication cookies from being captured and tampered with while crossing the network, ensure that you use Secure Sockets Layer (SSL) with all pages that require authenticated access and restrict forms authentication tickets to SSL channels.
- Partition the site for SSL. This allows you to avoid using SSL for the entire site.
- Do not persist forms authentication cookies. Do not persist authentication cookies because they are stored in the user's profile on the client computer and can be stolen if an attacker gets physical access to the user's computer.
- Consider reducing ticket lifetime. Consider reducing the cookie lifetime to reduce the time window in which an attacker can use a captured cookie to gain access to your application with a spoofed identity.
- Consider using a fixed expiration. In scenarios where you cannot use SSL, consider setting slidingExpiration="false".
- Enforce strong user management policies. Use and enforce strong passwords for all user accounts to ensure that people cannot guess one another's passwords and to mitigate the risk posed by dictionary attacks.
- Enforce password complexity rules. Validate passwords entered through the CreateUserWizard control, by setting its PasswordRegularExpression property to an appropriate regular expression. Also configure the membership provider on the server to use the same regular expression.
- Perform effective data validation on all requests. Perform strict data validation to minimize the possibilities of SQL injection and cross-site scripting.
- Use distinct cookie names and paths. By ensuring unique cookie names and paths, you prevent possible problems that can occur when hosting multiple applications on the same server.
- Keep authentication and personalization cookies separate. Keep personalization cookies that contain user-specific preferences and non-sensitive data separate from authentication cookies.
- Use absolute URLs for navigation. This is to avoid potential issues caused by redirecting from HTTP to HTTPS pages.
Once you are done with the authentication there are a number of features that you might want to explore. For example, one thing I needed was the ability to query the AD for verifying usernames when they are put in one of the admin screens. For that you need to put the line enableSearchMethods ="true" in your membership provider and you will have access to search functions.
MembershipUserCollection users = Membership.FindUsersByName(username);
string email = users[username].Email;
The search function returns you a collection of users matching the criteria and once you get this collection you can get individual users properties set in the AD. For example in this case I needed the email of the user to send an information email regarding the executed process.
I am pasting links to two MSDN articles which will allow you to explore this further. At the end of the first article you will find a table of all the properties you can set in you membership provider which will allow you to use almost all services provided by the AD.
How To: Use Forms Authentication with Active Directory in ASP.NET 2.0
The second article discusses specifically the security considerations of using this membership provider and this might of use when you are looking to tune the security of your site for a specific environment.
How To: Protect Forms Authentication in ASP.NET 2.0
Wally is my Guru
Generate PDF using SSRS
While looking for a method to programmatically generate PDF I came across the possibility of using SQL Server Reporting Services for the job. It actually has a number of possible rendering options, among them are "XML, NULL, CSV, IMAGE, PDF, HTML4.0, HTML3.2, MHTML, EXCEL, and HTMLOWC".
The problem with generating PDF is that there are two components to the document, the format and the data. The format part is the real pain that on has to deal with, date can then simply put in placeholders. SSRS simplifies this by allowing you to generate the PDF report by first creating the report, using some data from the database, in its own designer. Once the report is designed you can use the web services exposed by reporting services to save it any of those formats.
The SSRS web service can be found at http://server/reportserver/reportservice.asmx
After adding this service reference you will find the following nifty function for rendering the report in any format you like.
public Byte[] Render(
string Report,
string Format,
string HistoryID,
string DeviceInfo,
[Namespace].ParameterValue[] Parameters,
[Namespace].DataSourceCredentials[] Credentials,
string ShowHideToggle,
out string Encoding,
out string MimeType,
out [Namespace].ParameterValue[] ParametersUsed,
out [Namespace].Warning[] Warnings
out string[] StreamIds);
Member of [Namespace].ReportingService
According to the documentation the parameters are defined as following:
Parameters
- Report
- The full path name of the report.
- Format
- The format in which to render the report. This argument maps to a rendering extension. Supported extensions are XML, NULL, CSV, IMAGE, PDF, HTML4.0, HTML3.2, MHTML, EXCEL, and HTMLOWC.
- HistoryID
- Optional. The unique identifier of a report history snapshot to render for the specified report. The identifier is based on the date and time the report history was created.
- DeviceInfo
- An XML string that contains the device-specific content that is required by the rendering extension specified in the Format parameter. For more information about device information settings for specific output formats, see Device Information Settings.
- Parameters
- Optional. An array of ParameterValue[] objects that represent the report-specific parameters.
- Credentials
- Optional. An array of DataSourceCredentials[] objects that contains the data source credentials.
- ShowHideToggle
- Optional. The Show/Hide toggle ID.
- Encoding
- [out] The encoding used when report server renders the contents of the report.
- MimeType
- [out] The MIME type of the rendered report.
- ParametersUsed
- [out] An array of ParameterValue[] objects representing the query parameters, if any, that are stored along with the report. This parameter returns a value only if the report being rendered is a report history snapshot.
- Warnings
- [out] An array of Warning[] objects that describes any warnings that occurred during report processing.
- StreamIds
- [out] The stream identifiers. These IDs are passed to the RenderStream method. You can use them to render the external resources (images, etc.) that are associated with a given report.
Return Value
A Byte[] array of the report in the specified format. For more information about this data type, see "Byte Structure" in the .NET Framework documentation.
The following piece of code may be used to generate a PDF of the report you created.
private void RenderTest_Click(object sender, System.EventArgs e)
{
RSWebReference.ReportingService rs = new RSWebReference.ReportingService();
rs.Credentials = System.Net.CredentialCache.DefaultCredentials;
Byte[] result;
string encoding;
string mimetype;
ParameterValue[] parametersUsed;
Warning[] warnings;
string[] streamids;
result = rs.Render("/SampleReports/Company Sales","PDF",null,null,null,null,null,out encoding,out mimetype,out parametersUsed,out warnings,out streamids);
Response.ClearContent();
Response.AppendHeader("content-length", result.Length.ToString());
Response.ContentType = "application/pdf";
Response.BinaryWrite(result);
Response.Flush();
Response.Close();
}
If the reporting service is not satisfying your requirements or you simply don't have reporting service available then you can use on of the following libraries to generate PDF through your own code: C# open-source PDF Libraries
Render Method on MSDN
PDF Generation KB