History

Renamed folders and separated GSF.Media and GSF.Net into separate projects.

StephenCWills committed 14 years ago

Commit ac1ef661 parent 45bce55628 files · +733 −461Browse files

Showing the changes to Source/Libraries/GSF.Web/SecurityModule.cs (1 of 628 files). Show all

Unified · Split

Source/Libraries/GSF.Web/SecurityModule.cs+305−0
@@ -0,0 +1,305 @@
1+//******************************************************************************************************
2+// SecurityModule.cs - Gbtc
3+//
4+// Copyright © 2010, Grid Protection Alliance. All Rights Reserved.
5+//
6+// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
7+// the NOTICE file distributed with this work for additional information regarding copyright ownership.
8+// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may
9+// not use this file except in compliance with the License. You may obtain a copy of the License at:
10+//
11+// http://www.opensource.org/licenses/eclipse-1.0.php
12+//
13+// Unless agreed to in writing, the subject software distributed under the License is distributed on an
14+// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
15+// License for the specific language governing permissions and limitations.
16+//
17+// Code Modification History:
18+// ----------------------------------------------------------------------------------------------------
19+// 03/31/2010 - Pinal C. Patel
20+// Generated original version of source code.
21+// 05/27/2010 - Pinal C. Patel
22+// Added usage example to code comments.
23+// 06/30/2010 - Pinal C. Patel
24+// Modified redirection logic to support security of static resources (*.txt, *.pdf, *.exe).
25+// 07/01/2010 - Pinal C. Patel
26+// Modified redirection logic to allow for custom redirection using customErrors settings.
27+// 08/11/2010 - Pinal C. Patel
28+// Made key methods virtual for extensibility.
29+// 10/14/2010 - Pinal C. Patel
30+// Modified GetResourceName() to return path and query for consistency with SecurityPolicy.
31+// 01/06/2011 - Pinal C. Patel
32+// Implemented logic to use RestrictAccessAttribute for access control on the requested resource.
33+// 06/09/2011 - Pinal C. Patel
34+// Added null reference check in IsAccessRestricted() method.
35+// 07/29/2011 - Pinal C. Patel
36+// Made the referral URL passed to SecurityPortal.aspx page relative so redirection work correctly
37+// when reverse proxy is involved where requested URL that the web server sees is different than
38+// what the user requested.
39+// 08/18/2011 - Pinal C. Patel
40+// Made Redirect() overridable by deriving classes to control the redirection behavior.
41+// 08/19/2011 - Pinal C. Patel
42+// Changed the type input parameter for Redirect() from int to HttpStatusCode.
43+// 10/8/2012 - Danyelle Gilliam
44+// Modified Header
45+//
46+//******************************************************************************************************
47+
48+using GSF.Configuration;
49+using GSF.Security;
50+using GSF.Web.Hosting;
51+using System;
52+using System.Net;
53+using System.Web;
54+using System.Web.Configuration;
55+using System.Web.Hosting;
56+using System.Web.SessionState;
57+
58+namespace GSF.Web
59+{
60+ #region [ Enumerations ]
61+
62+ #endregion
63+
64+ /// <summary>
65+ /// Represents an <see cref="IHttpModule">HTTP module</see> that can be used to enable site-wide role-based security.
66+ /// </summary>
67+ /// <example>
68+ /// Required config file entries:
69+ /// <code>
70+ /// <![CDATA[
71+ /// <?xml version="1.0"?>
72+ /// <configuration>
73+ /// <configSections>
74+ /// <section name="categorizedSettings" type="GSF.Configuration.CategorizedSettingsSection, GSF.Core" />
75+ /// </configSections>
76+ /// <categorizedSettings>
77+ /// <securityProvider>
78+ /// <add name="ApplicationName" value="" description="Name of the application being secured as defined in the backend security datastore."
79+ /// encrypted="false" />
80+ /// <add name="ConnectionString" value="" description="Connection string to be used for connection to the backend security datastore."
81+ /// encrypted="false" />
82+ /// <add name="ProviderType" value="GSF.Security.LdapSecurityProvider, GSF.Security"
83+ /// description="The type to be used for enforcing security." encrypted="false" />
84+ /// <add name="IncludedResources" value="*/*.*=*" description="Semicolon delimited list of resources to be secured along with role names."
85+ /// encrypted="false" />
86+ /// <add name="ExcludedResources" value="*/WebResource.axd*;*/SecurityPortal.aspx*"
87+ /// description="Semicolon delimited list of resources to be excluded from being secured."
88+ /// encrypted="false" />
89+ /// <add name="NotificationSmtpServer" value="localhost" description="SMTP server to be used for sending out email notification messages."
90+ /// encrypted="false" />
91+ /// <add name="NotificationSenderEmail" value="sender@company.com" description="Email address of the sender of email notification messages."
92+ /// encrypted="false" />
93+ /// </securityProvider>
94+ /// <activeDirectory>
95+ /// <add name="PrivilegedDomain" value="" description="Domain of privileged domain user account."
96+ /// encrypted="false" />
97+ /// <add name="PrivilegedUserName" value="" description="Username of privileged domain user account."
98+ /// encrypted="false" />
99+ /// <add name="PrivilegedPassword" value="" description="Password of privileged domain user account."
100+ /// encrypted="true" />
101+ /// </activeDirectory>
102+ /// </categorizedSettings>
103+ /// <system.web>
104+ /// <authentication mode="Windows"/>
105+ /// <httpModules>
106+ /// <add name="SecurityModule" type="GSF.Web.SecurityModule, GSF.Web" />
107+ /// </httpModules>
108+ /// </system.web>
109+ /// </configuration>
110+ /// ]]>
111+ /// </code>
112+ /// </example>
113+ /// <seealso cref="ISecurityProvider"/>
114+ public class SecurityModule : IHttpModule
115+ {
116+ #region [ Members ]
117+
118+ // Nested Types
119+
120+ /// <summary>
121+ /// A handler used to force the SessionStateModule to load session state.
122+ /// </summary>
123+ private class SessionEnabledHandler : IHttpHandler, IRequiresSessionState
124+ {
125+ public IHttpHandler OriginalHandler;
126+
127+ /// <summary>
128+ /// Initializes a new instance of the <see cref="SessionEnabledHandler"/> class.
129+ /// </summary>
130+ /// <param name="originalHandler">The original handler object.</param>
131+ public SessionEnabledHandler(IHttpHandler originalHandler)
132+ {
133+ OriginalHandler = originalHandler;
134+ }
135+
136+ /// <summary>
137+ /// This method will never get called.
138+ /// </summary>
139+ public void ProcessRequest(HttpContext context)
140+ {
141+ throw new NotSupportedException();
142+ }
143+
144+ /// <summary>
145+ /// Returns false since class has a member.
146+ /// </summary>
147+ public bool IsReusable
148+ {
149+ get { return false; }
150+ }
151+ }
152+
153+ // Fields
154+ private HttpApplication m_application;
155+
156+ #endregion
157+
158+ #region [ Properties ]
159+
160+ /// <summary>
161+ /// Gets the current <see cref="HttpApplication"/> instance.
162+ /// </summary>
163+ protected HttpApplication Application
164+ {
165+ get
166+ {
167+ return m_application;
168+ }
169+ }
170+
171+ #endregion
172+
173+ #region [ Methods ]
174+
175+ /// <summary>
176+ /// Initializes the <see cref="SecurityModule"/>.
177+ /// </summary>
178+ /// <param name="context">An <see cref="HttpApplication"/> object.</param>
179+ public void Init(HttpApplication context)
180+ {
181+ m_application = context;
182+ m_application.PostMapRequestHandler += Application_PostMapRequestHandler;
183+ m_application.PostAcquireRequestState += Application_PostAcquireRequestState;
184+ m_application.PreRequestHandlerExecute += Application_PreRequestHandlerExecute;
185+
186+ if (!(HostingEnvironment.VirtualPathProvider is EmbeddedResourcePathProvider))
187+ HostingEnvironment.RegisterVirtualPathProvider(new EmbeddedResourcePathProvider());
188+ }
189+
190+ /// <summary>
191+ /// Releases the resources used by <see cref="SecurityModule"/>.
192+ /// </summary>
193+ public void Dispose()
194+ {
195+ m_application.PostMapRequestHandler -= Application_PostMapRequestHandler;
196+ m_application.PostAcquireRequestState -= Application_PostAcquireRequestState;
197+ m_application.PreRequestHandlerExecute -= Application_PreRequestHandlerExecute;
198+ }
199+
200+ /// <summary>
201+ /// Redirects the client browser based on the specified <paramref name="httpStatusCode"/>
202+ /// </summary>
203+ /// <param name="httpStatusCode"><see cref="HttpStatusCode"/> to be used for the redirect.</param>
204+ protected virtual void Redirect(HttpStatusCode httpStatusCode)
205+ {
206+ int statusCode = (int)httpStatusCode;
207+ if (m_application.Context.IsCustomErrorEnabled)
208+ {
209+ // Defer redirect to customErrors settings in the config file to allow for custom error pages.
210+ ConfigurationFile configFile = ConfigurationFile.Current;
211+ CustomErrorsSection customErrors = configFile.Configuration.GetSection("system.web/customErrors") as CustomErrorsSection;
212+ if (customErrors != null && customErrors.Errors[statusCode.ToString()] != null)
213+ {
214+ // Set status code for the response.
215+ m_application.Context.Response.StatusCode = statusCode;
216+ // Throw exception for ASP.NET pipeline to takeover processing.
217+ throw new HttpException(statusCode, string.Format("Security exception (HTTP status code: {0})", statusCode));
218+ }
219+ }
220+
221+ // Abruptly ending the processing caused by a redirect does not work well when processing static content.
222+ string redirectUrl = string.Format("~/SecurityPortal.aspx?s={0}&r={1}", statusCode, HttpUtility.UrlEncode(VirtualPathUtility.ToAppRelative(m_application.Request.Url.PathAndQuery)));
223+ if (m_application.Context.Handler is DefaultHttpHandler)
224+ // Accessed resource is static.
225+ m_application.Context.Response.Redirect(redirectUrl, false);
226+ else
227+ // Accessed resource is dynamic.
228+ m_application.Context.Response.Redirect(redirectUrl, true);
229+ }
230+
231+ /// <summary>
232+ /// Gets the name of resource being accessed.
233+ /// </summary>
234+ /// <returns><see cref="HttpApplication.Request"/>.<see cref="HttpRequest.Url"/>.<see cref="Uri.PathAndQuery"/> property value.</returns>
235+ protected virtual string GetResourceName()
236+ {
237+ return m_application.Request.Url.PathAndQuery;
238+ }
239+
240+ /// <summary>
241+ /// Determines if access to the requested resource is restricted by <see cref="RestrictAccessAttribute"/>.
242+ /// </summary>
243+ /// <returns>true if access to the requested resource is restricted, otherwise false.</returns>
244+ protected virtual bool IsAccessRestricted()
245+ {
246+ // Check for the request handler.
247+ IHttpHandler handler = m_application.Context.Handler;
248+ if (handler == null)
249+ return false;
250+
251+ // Evaluate access restriction if defined.
252+ object[] attributes = handler.GetType().GetCustomAttributes(typeof(RestrictAccessAttribute), true);
253+ if (attributes.Length > 0)
254+ return !((RestrictAccessAttribute)attributes[0]).CheckAccess();
255+ else
256+ return false;
257+ }
258+
259+ private void Application_PostMapRequestHandler(object sender, EventArgs e)
260+ {
261+ if (!SecurityProviderUtility.IsResourceSecurable(GetResourceName()))
262+ return;
263+
264+ if (m_application.Context.Handler is IReadOnlySessionState ||
265+ m_application.Context.Handler is IRequiresSessionState)
266+ // no need to replace the current handler
267+ return;
268+
269+ // swap the current handler
270+ m_application.Context.Handler = new SessionEnabledHandler(m_application.Context.Handler);
271+ }
272+
273+ private void Application_PostAcquireRequestState(object sender, EventArgs e)
274+ {
275+ if (!SecurityProviderUtility.IsResourceSecurable(GetResourceName()))
276+ return;
277+
278+ SessionEnabledHandler handler = HttpContext.Current.Handler as SessionEnabledHandler;
279+ if (handler != null)
280+ // set the original handler back
281+ HttpContext.Current.Handler = handler.OriginalHandler;
282+ }
283+
284+ private void Application_PreRequestHandlerExecute(object sender, EventArgs e)
285+ {
286+ string resource = GetResourceName();
287+ if (!SecurityProviderUtility.IsResourceSecurable(resource))
288+ return;
289+
290+ if (SecurityProviderCache.CurrentProvider == null)
291+ SecurityProviderCache.CurrentProvider = SecurityProviderUtility.CreateProvider(string.Empty);
292+
293+ if (!m_application.User.Identity.IsAuthenticated)
294+ // Failed to authenticate user.
295+ Redirect(HttpStatusCode.Unauthorized);
296+
297+ if (IsAccessRestricted() ||
298+ !SecurityProviderUtility.IsResourceAccessible(resource))
299+ // User does not have access to the resource.
300+ Redirect(HttpStatusCode.Forbidden);
301+ }
302+
303+ #endregion
304+ }
305+}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t