1 //------------------------------------------------------------------------------ 2 // <copyright file="LoginView.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 //------------------------------------------------------------------------------ 6 7 namespace System.Web.UI.WebControls { 8 9 using System.Collections; 10 using System.ComponentModel; 11 using System.Security.Permissions; 12 using System.Security.Principal; 13 using System.Web.Security; 14 using System.Web.UI; 15 16 17 /// <devdoc> 18 /// Renders exactly one of its templates, chosen by whether a user is logged in 19 /// and the roles that contain the user. 20 /// </devdoc> 21 [ 22 Bindable(false), 23 ParseChildren(true), 24 PersistChildren(false), 25 Designer("System.Web.UI.Design.WebControls.LoginViewDesigner," + AssemblyRef.SystemDesign), 26 DefaultProperty("CurrentView"), 27 DefaultEvent("ViewChanged"), 28 Themeable(true), 29 ] 30 public class LoginView : Control, INamingContainer { 31 32 private RoleGroupCollection _roleGroups; 33 private ITemplate _loggedInTemplate; 34 private ITemplate _anonymousTemplate; 35 36 private int _templateIndex; 37 38 private const int anonymousTemplateIndex = 0; 39 private const int loggedInTemplateIndex = 1; 40 private const int roleGroupStartingIndex = 2; 41 42 private static readonly object EventViewChanging = new object(); 43 private static readonly object EventViewChanged = new object(); 44 45 46 /// <devdoc> 47 /// Template shown when no user is logged in. 48 /// </devdoc> 49 [ 50 Browsable(false), 51 DefaultValue(null), 52 PersistenceMode(PersistenceMode.InnerProperty), 53 TemplateContainer(typeof(LoginView)), 54 ] 55 public virtual ITemplate AnonymousTemplate { 56 get { 57 return _anonymousTemplate; 58 } 59 set { 60 _anonymousTemplate = value; 61 } 62 } 63 64 [ 65 Browsable(true), 66 ] 67 public override bool EnableTheming { 68 get { 69 return base.EnableTheming; 70 } 71 set { 72 base.EnableTheming = value; 73 } 74 } 75 76 [ 77 Browsable(true), 78 ] 79 public override string SkinID { 80 get { 81 return base.SkinID; 82 } 83 set { 84 base.SkinID = value; 85 } 86 } 87 88 89 90 /// <devdoc> 91 /// Copied from CompositeControl. This control does not extend CompositeControl because it should not be a WebControl. 92 /// </devdoc> 93 public override ControlCollection Controls { 94 get { 95 EnsureChildControls(); 96 return base.Controls; 97 } 98 } 99 100 101 /// <devdoc> 102 /// Copied from CompositeControl. This control does not extend CompositeControl because it should not be a WebControl. 103 /// Does not call Base.DataBind(), since we need to call EnsureChildControls() between 104 /// OnDataBinding() and DataBindChildren(). 105 /// </devdoc> DataBind()106 public override void DataBind() { 107 // Do our own databinding 108 OnDataBinding(EventArgs.Empty); 109 110 EnsureChildControls(); 111 112 // Do all of our children's databinding 113 DataBindChildren(); 114 } 115 116 117 /// <devdoc> 118 /// Template shown when a user is logged in, but the user is not in any role associated with a template. 119 /// </devdoc> 120 [ 121 Browsable(false), 122 DefaultValue(null), 123 PersistenceMode(PersistenceMode.InnerProperty), 124 TemplateContainer(typeof(LoginView)), 125 ] 126 public virtual ITemplate LoggedInTemplate { 127 get { 128 return _loggedInTemplate; 129 } 130 set { 131 _loggedInTemplate = value; 132 } 133 } 134 135 136 /// <devdoc> 137 /// Maps groups of roles to templates. 138 /// </devdoc> 139 [ 140 WebCategory("Behavior"), 141 MergableProperty(false), 142 Themeable(false), 143 Filterable(false), 144 PersistenceMode(PersistenceMode.InnerProperty), 145 WebSysDescription(SR.LoginView_RoleGroups) 146 ] 147 public virtual RoleGroupCollection RoleGroups { 148 get { 149 if (_roleGroups == null) { 150 _roleGroups = new RoleGroupCollection(); 151 } 152 return _roleGroups; 153 } 154 } 155 156 /// <devdoc> 157 /// Index of the template rendered on the previous page load. Saved in ControlState. 158 /// 0: AnonymousTemplate 159 /// 1: LoggedInTemplate 160 /// >=2: RoleGroup template with index n-2 161 /// </devdoc> 162 private int TemplateIndex { 163 get { 164 return _templateIndex; 165 } 166 set { 167 if (value != TemplateIndex) { 168 OnViewChanging(EventArgs.Empty); 169 _templateIndex = value; 170 ChildControlsCreated = false; 171 OnViewChanged(EventArgs.Empty); 172 } 173 } 174 } 175 176 177 /// <devdoc> 178 /// Raised after the view is changed. 179 /// </devdoc> 180 [ 181 WebCategory("Action"), 182 WebSysDescription(SR.LoginView_ViewChanged) 183 ] 184 public event EventHandler ViewChanged { 185 add { 186 Events.AddHandler(EventViewChanged, value); 187 } 188 remove { 189 Events.RemoveHandler(EventViewChanged, value); 190 } 191 } 192 193 194 /// <devdoc> 195 /// Raised before the view is changed. Not cancellable, because the view is changed 196 /// when the logged-in user changes, and it wouldn't make sense to cancel this. 197 /// </devdoc> 198 [ 199 WebCategory("Action"), 200 WebSysDescription(SR.LoginView_ViewChanging) 201 ] 202 public event EventHandler ViewChanging { 203 add { 204 Events.AddHandler(EventViewChanging, value); 205 } 206 remove { 207 Events.RemoveHandler(EventViewChanging, value); 208 } 209 } 210 211 212 /// <devdoc> 213 /// Instantiate the appropriate template. 214 /// </devdoc> CreateChildControls()215 protected internal override void CreateChildControls() { 216 Controls.Clear(); 217 218 // For the first request, set _templateIndex now, so the correct template is 219 // instantiated and we do not raise the ViewChanging/ViewChanged events. 220 Page page = Page; 221 if (page != null && !page.IsPostBack && !DesignMode) { 222 _templateIndex = GetTemplateIndex(); 223 } 224 225 int templateIndex = TemplateIndex; 226 ITemplate template = null; 227 switch (templateIndex) { 228 case anonymousTemplateIndex: 229 template = AnonymousTemplate; 230 break; 231 case loggedInTemplateIndex: 232 template = LoggedInTemplate; 233 break; 234 default: 235 int roleGroupIndex = templateIndex - roleGroupStartingIndex; 236 RoleGroupCollection roleGroups = RoleGroups; 237 if (0 <= roleGroupIndex && roleGroupIndex < roleGroups.Count) { 238 template = roleGroups[roleGroupIndex].ContentTemplate; 239 } 240 break; 241 } 242 243 if (template != null) { 244 Control templateContainer = new Control(); 245 template.InstantiateIn(templateContainer); 246 Controls.Add(templateContainer); 247 } 248 } 249 250 [ 251 EditorBrowsable(EditorBrowsableState.Never), 252 ] Focus()253 public override void Focus() { 254 throw new NotSupportedException(SR.GetString(SR.NoFocusSupport, this.GetType().Name)); 255 } 256 257 /// <devdoc> 258 /// Loads the control state for those properties that should persist across postbacks 259 /// even when EnableViewState=false. 260 /// </devdoc> LoadControlState(object savedState)261 protected internal override void LoadControlState(object savedState) { 262 if (savedState != null) { 263 Pair state = (Pair)savedState; 264 if (state.First != null) { 265 base.LoadControlState(state.First); 266 } 267 if (state.Second != null) { 268 _templateIndex = (int)state.Second; 269 } 270 } 271 } 272 273 OnInit(EventArgs e)274 protected internal override void OnInit(EventArgs e) { 275 base.OnInit(e); 276 if (Page != null) { 277 Page.RegisterRequiresControlState(this); 278 } 279 } 280 281 282 /// <devdoc> 283 /// Sets the TemplateIndex based on the current user. 284 /// </devdoc> OnPreRender(EventArgs e)285 protected internal override void OnPreRender(EventArgs e) { 286 base.OnPreRender(e); 287 288 TemplateIndex = GetTemplateIndex(); 289 290 // This is called in Control.PreRenderRecursiveInteral, but we need to call it again 291 // since we may have changed the TemplateIndex 292 EnsureChildControls(); 293 } 294 295 296 /// <devdoc> 297 /// Raises the ViewChanged event. 298 /// </devdoc> OnViewChanged(EventArgs e)299 protected virtual void OnViewChanged(EventArgs e) { 300 EventHandler handler = (EventHandler)Events[EventViewChanged]; 301 if (handler != null) { 302 handler(this, e); 303 } 304 } 305 306 307 /// <devdoc> 308 /// Raises the ViewChanging event. 309 /// </devdoc> OnViewChanging(EventArgs e)310 protected virtual void OnViewChanging(EventArgs e) { 311 EventHandler handler = (EventHandler)Events[EventViewChanging]; 312 if (handler != null) { 313 handler(this, e); 314 } 315 } 316 Render(HtmlTextWriter writer)317 protected internal override void Render(HtmlTextWriter writer) { 318 EnsureChildControls(); 319 base.Render(writer); 320 } 321 322 /// <devdoc> 323 /// Saves the control state for those properties that should persist across postbacks 324 /// even when EnableViewState=false. 325 /// </devdoc> SaveControlState()326 protected internal override object SaveControlState() { 327 object baseState = base.SaveControlState(); 328 if (baseState != null || _templateIndex != 0) { 329 object templateIndexState = null; 330 331 if (_templateIndex != 0) { 332 templateIndexState = _templateIndex; 333 } 334 return new Pair(baseState, templateIndexState); 335 } 336 return null; 337 } 338 339 340 /// <devdoc> 341 /// Allows the designer to set the TemplateIndex, so the different templates can be shown in the designer. 342 /// </devdoc> 343 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)] SetDesignModeState(IDictionary data)344 protected override void SetDesignModeState(IDictionary data) { 345 if (data != null) { 346 object o = data["TemplateIndex"]; 347 if (o != null) { 348 TemplateIndex = (int)o; 349 350 // Note: we always recreate the child controls in the designer to correctly handle the case of 351 // the currently selected role group being deleted. This is necessary because the 352 // setter for TemplateIndex won't recreate the controls if the TemplateIndex is unchanged, 353 // which is the case when deleting all but the last role group. [Fix for Bug 148406] 354 ChildControlsCreated = false; 355 } 356 } 357 } 358 GetTemplateIndex()359 private int GetTemplateIndex() { 360 if (!DesignMode && Page != null && Page.Request.IsAuthenticated) { 361 IPrincipal user = LoginUtil.GetUser(this); 362 int roleGroupIndex = -1; 363 364 // Unlikely but possible for Page.Request.IsAuthenticated to be true and 365 // user to be null. 366 if (user != null) { 367 roleGroupIndex = RoleGroups.GetMatchingRoleGroupInternal(user); 368 } 369 370 if (roleGroupIndex >= 0) { 371 return roleGroupIndex + roleGroupStartingIndex; 372 } 373 else { 374 return loggedInTemplateIndex; 375 } 376 } 377 else { 378 return anonymousTemplateIndex; 379 } 380 } 381 } 382 } 383