2 // System.Web.Security.SqlRoleProvider
5 // Ben Maurer (bmaurer@users.sourceforge.net)
6 // Chris Toshok (toshok@ximian.com)
9 // Copyright (c) 2005,2006 Novell, Inc (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Collections;
34 using System.Collections.Specialized;
36 using System.Data.Common;
37 using System.Configuration;
38 using System.Configuration.Provider;
39 using System.Web.Configuration;
41 namespace System.Web.Security {
43 public class SqlRoleProvider: RoleProvider {
45 string applicationName;
49 ConnectionStringSettings connectionString;
50 DbProviderFactory factory;
51 DbConnection connection;
53 void InitConnection ()
56 factory = ProvidersHelper.GetDbProviderFactory (connectionString.ProviderName);
57 if (connection == null) {
58 connection = factory.CreateConnection();
59 connection.ConnectionString = connectionString.ConnectionString;
63 void AddParameter (DbCommand command, string parameterName, string parameterValue)
65 DbParameter dbp = command.CreateParameter ();
66 dbp.ParameterName = parameterName;
67 dbp.Value = parameterValue;
68 dbp.Direction = ParameterDirection.Input;
69 command.Parameters.Add (dbp);
72 public override void AddUsersToRoles (string [] usernames, string [] rolenames)
74 string commandText = @"
75 INSERT INTO dbo.aspnet_UsersInRoles (UserId, RoleId)
76 SELECT dbo.aspnet_Users.UserId, dbo.aspnet_Roles.RoleId
77 FROM dbo.aspnet_Users, dbo.aspnet_Roles, dbo.aspnet_Applications
78 WHERE dbo.aspnet_Users.ApplicationId = dbo.aspnet_Applications.ApplicationId
79 AND dbo.aspnet_Roles.ApplicationId = dbo.aspnet_Applications.ApplicationId
80 AND dbo.aspnet_Applications.LoweredApplicationName = LOWER(@ApplicationName)
81 AND dbo.aspnet_Users.LoweredUserName = LOWER(@UserName)
82 AND dbo.aspnet_Roles.LoweredRoleName = LOWER(@RoleName)
88 foreach (string u in usernames) {
90 throw new ArgumentNullException ("null element in usernames array");
91 if (h.ContainsKey (u))
92 throw new ArgumentException ("duplicate element in usernames array");
93 if (u.Length == 0 || u.Length > 256 || u.IndexOf (",") != -1)
94 throw new ArgumentException ("element in usernames array in illegal format");
99 foreach (string r in usernames) {
101 throw new ArgumentNullException ("null element in usernames array");
102 if (h.ContainsKey (r))
103 throw new ArgumentException ("duplicate element in usernames array");
104 if (r.Length == 0 || r.Length > 256 || r.IndexOf (",") != -1)
105 throw new ArgumentException ("element in usernames array in illegal format");
111 bool closed = connection.State == ConnectionState.Closed;
115 DbTransaction trans = connection.BeginTransaction ();
118 foreach (string username in usernames) {
120 foreach (string rolename in rolenames) {
122 /* add the user/role combination to dbo.aspnet_UsersInRoles */
123 DbCommand command = factory.CreateCommand ();
124 command.Transaction = trans;
125 command.CommandText = commandText;
126 command.Connection = connection;
127 command.CommandType = CommandType.Text;
128 AddParameter (command, "RoleName", rolename);
129 AddParameter (command, "UserName", username);
130 AddParameter (command, "ApplicationName", ApplicationName);
132 if (command.ExecuteNonQuery() != 1)
133 throw new ProviderException ("failed to create new user/role association.");
139 catch (Exception e) {
141 if (e is ProviderException)
144 throw new ProviderException ("", e);
152 public override void CreateRole (string rolename)
154 string commandText = @"
155 INSERT INTO dbo.aspnet_Roles
156 (ApplicationId, RoleName, LoweredRoleName)
157 VALUES ((SELECT ApplicationId FROM dbo.aspnet_Applications WHERE LoweredApplicationName = LOWER(@ApplicationName)), @RoleName, LOWER(@RoleName))
159 if (rolename == null)
160 throw new ArgumentNullException ("rolename");
162 if (rolename.Length == 0 || rolename.Length > 256 || rolename.IndexOf (",") != -1)
163 throw new ArgumentException ("rolename is in invalid format");
166 bool closed = connection.State == ConnectionState.Closed;
170 DbCommand command = factory.CreateCommand ();
171 command.CommandText = commandText;
172 command.Connection = connection;
173 command.CommandType = CommandType.Text;
174 AddParameter (command, "ApplicationName", ApplicationName);
175 AddParameter (command, "RoleName", rolename);
177 if (command.ExecuteNonQuery() != 1)
178 throw new ProviderException ("failed to create new role.");
185 public override bool DeleteRole (string rolename, bool throwOnPopulatedRole)
187 if (rolename == null)
188 throw new ArgumentNullException ("rolename");
190 if (rolename.Length == 0 || rolename.Length > 256 || rolename.IndexOf (",") != -1)
191 throw new ArgumentException ("rolename is in invalid format");
194 bool closed = connection.State == ConnectionState.Closed;
199 if (throwOnPopulatedRole) {
200 command = factory.CreateCommand ();
201 command.CommandText = @"
203 FROM dbo.aspnet_UsersInRoles, dbo.aspnet_Roles, dbo.aspnet_Users, dbo.aspnet_Applications
204 WHERE dbo.aspnet_Roles.ApplicationId = dbo.aspnet_Applications.ApplicationId
205 AND dbo.aspnet_UsersInRoles.RoleId = dbo.aspnet_Roles.RoleId
206 AND dbo.aspnet_Applications.LoweredApplicationName = LOWER(@ApplicationName)
207 AND dbo.aspnet_Roles.LoweredRoleName = LOWER(@RoleName)";
208 command.Connection = connection;
209 command.CommandType = CommandType.Text;
210 AddParameter (command, "ApplicationName", ApplicationName);
211 AddParameter (command, "RoleName", rolename);
213 int count = (int)command.ExecuteScalar ();
215 throw new ProviderException (String.Format ("The role '{0}' has users in it and can't be deleted", rolename));
218 /* XXX are we really supposed to delete all the user/role associations in this case? */
219 command = factory.CreateCommand ();
220 command.CommandText = @"
221 DELETE dbo.aspnet_UsersInRoles FROM dbo.aspnet_UsersInRoles, dbo.aspnet_Roles, dbo.aspnet_Applications
222 WHERE dbo.aspnet_UsersInRoles.RoleId = dbo.aspnet_Roles.RoleId
223 AND dbo.aspnet_Roles.ApplicationId = dbo.aspnet_Applications.ApplicationId
224 AND dbo.aspnet_Roles.LoweredRoleName = LOWER(@RoleName)
225 AND dbo.aspnet_Applications.LoweredApplicationName = LOWER(@ApplicationName)";
226 command.Connection = connection;
227 command.CommandType = CommandType.Text;
228 AddParameter (command, "RoleName", rolename);
229 AddParameter (command, "ApplicationName", ApplicationName);
231 command.ExecuteNonQuery ();
234 command = factory.CreateCommand ();
235 command.CommandText = @"
236 DELETE dbo.aspnet_Roles FROM dbo.aspnet_Roles, dbo.aspnet_Applications
237 WHERE dbo.aspnet_Roles.ApplicationId = dbo.aspnet_Applications.ApplicationId
238 AND dbo.aspnet_Applications.LoweredApplicationName = LOWER(@ApplicationName)
239 AND dbo.aspnet_Roles.LoweredRoleName = LOWER(@RoleName)";
240 command.Connection = connection;
241 command.CommandType = CommandType.Text;
242 AddParameter (command, "ApplicationName", ApplicationName);
243 AddParameter (command, "RoleName", rolename);
245 bool rv = command.ExecuteNonQuery() == 1;
253 public override string[] FindUsersInRole (string roleName, string usernameToMatch)
255 string commandTextFormat = @"
256 SELECT dbo.aspnet_Users.UserName
257 FROM dbo.aspnet_Users, dbo.aspnet_Roles, dbo.aspnet_UsersInRoles, dbo.aspnet_Applications
258 WHERE dbo.aspnet_Roles.ApplicationId = dbo.aspnet_Applications.ApplicationId
259 AND dbo.aspnet_Users.ApplicationId = dbo.aspnet_Applications.ApplicationId
260 AND dbo.aspnet_UsersInRoles.UserId = dbo.aspnet_Users.UserId
261 AND dbo.aspnet_UsersInRoles.RoleId = dbo.aspnet_Roles.RoleId
262 AND dbo.aspnet_Roles.LoweredRoleName = LOWER(@RoleName)
263 AND dbo.aspnet_Applications.LoweredApplicationName = LOWER(@ApplicationName)
264 AND dbo.aspnet_Users.UserName {0} @UsernameToMatch
266 if (roleName == null)
267 throw new ArgumentNullException ("roleName");
268 if (usernameToMatch == null)
269 throw new ArgumentNullException ("usernameToMatch");
271 if (roleName.Length == 0 || roleName.Length > 256 || roleName.IndexOf (",") != -1)
272 throw new ArgumentException ("roleName is in invalid format");
273 if (usernameToMatch.Length == 0 || usernameToMatch.Length > 256)
274 throw new ArgumentException ("usernameToMatch is in invalid format");
278 bool useLike = usernameToMatch.IndexOf ("%") != -1;
279 DbCommand command = factory.CreateCommand ();
280 command.CommandText = String.Format(commandTextFormat, useLike ? "LIKE" : "=");
281 command.Connection = connection;
282 command.CommandType = CommandType.Text;
283 AddParameter (command, "ApplicationName", ApplicationName);
284 AddParameter (command, "RoleName", roleName);
285 AddParameter (command, "UsernameToMatch", usernameToMatch);
287 DbDataReader reader = command.ExecuteReader ();
288 ArrayList userList = new ArrayList();
289 while (reader.Read())
290 userList.Add (reader.GetString(0));
293 return (string[])userList.ToArray(typeof (string));
296 public override string [] GetAllRoles ()
298 string commandText = @"
299 SELECT dbo.aspnet_Roles.RoleName
300 FROM dbo.aspnet_Roles, dbo.aspnet_Applications
301 WHERE dbo.aspnet_Roles.ApplicationId = dbo.aspnet_Applications.ApplicationId
302 AND dbo.aspnet_Applications.LoweredApplicationName = LOWER(@ApplicationName)
305 bool closed = connection.State == ConnectionState.Closed;
309 DbCommand command = factory.CreateCommand ();
310 command.CommandText = commandText;
311 command.Connection = connection;
312 command.CommandType = CommandType.Text;
313 AddParameter (command, "ApplicationName", ApplicationName);
315 DbDataReader reader = command.ExecuteReader ();
316 ArrayList roleList = new ArrayList();
317 while (reader.Read())
318 roleList.Add (reader.GetString(0));
324 return (string[])roleList.ToArray(typeof (string));
327 public override string [] GetRolesForUser (string username)
329 string commandText = @"
330 SELECT dbo.aspnet_Roles.RoleName
331 FROM dbo.aspnet_Roles, dbo.aspnet_UsersInRoles, dbo.aspnet_Users, dbo.aspnet_Applications
332 WHERE dbo.aspnet_Roles.RoleId = dbo.aspnet_UsersInRoles.RoleId
333 AND dbo.aspnet_Roles.ApplicationId = dbo.aspnet_Applications.ApplicationId
334 AND dbo.aspnet_UsersInRoles.UserId = dbo.aspnet_Users.UserId
335 AND dbo.aspnet_Users.LoweredUserName = LOWER(@UserName)
336 AND dbo.aspnet_Users.ApplicationId = dbo.aspnet_Applications.ApplicationId
337 AND dbo.aspnet_Applications.LoweredApplicationName = LOWER(@ApplicationName)
341 bool closed = connection.State == ConnectionState.Closed;
345 DbCommand command = factory.CreateCommand ();
346 command.CommandText = commandText;
347 command.Connection = connection;
348 command.CommandType = CommandType.Text;
349 AddParameter (command, "UserName", username);
350 AddParameter (command, "ApplicationName", ApplicationName);
352 DbDataReader reader = command.ExecuteReader ();
353 ArrayList roleList = new ArrayList();
354 while (reader.Read())
355 roleList.Add (reader.GetString(0));
361 return (string[])roleList.ToArray(typeof (string));
364 public override string [] GetUsersInRole (string rolename)
366 string commandText = @"
367 SELECT dbo.aspnet_Users.UserName
368 FROM dbo.aspnet_Roles, dbo.aspnet_UsersInRoles, dbo.aspnet_Users, dbo.aspnet_Applications
369 WHERE dbo.aspnet_Roles.RoleId = dbo.aspnet_UsersInRoles.RoleId
370 AND dbo.aspnet_Roles.ApplicationId = dbo.aspnet_Applications.ApplicationId
371 AND dbo.aspnet_UsersInRoles.UserId = dbo.aspnet_Users.UserId
372 AND dbo.aspnet_Roles.LoweredRoleName = LOWER(@RoleName)
373 AND dbo.aspnet_Users.ApplicationId = dbo.aspnet_Applications.ApplicationId
374 AND dbo.aspnet_Applications.LoweredApplicationName = LOWER(@ApplicationName)
378 bool closed = connection.State == ConnectionState.Closed;
382 DbCommand command = factory.CreateCommand ();
383 command.CommandText = commandText;
384 command.Connection = connection;
385 command.CommandType = CommandType.Text;
386 AddParameter (command, "RoleName", rolename);
387 AddParameter (command, "ApplicationName", ApplicationName);
389 DbDataReader reader = command.ExecuteReader ();
390 ArrayList userList = new ArrayList();
391 while (reader.Read())
392 userList.Add (reader.GetString(0));
398 return (string[])userList.ToArray(typeof (string));
402 public override void Initialize (string name, NameValueCollection config)
405 throw new ArgumentNullException ("config");
407 base.Initialize (name, config);
410 ApplicationName = config["applicationName"];
412 ApplicationName = "/";
414 string connectionStringName = config["connectionStringName"];
415 string commandTimeout = config["commandTimeout"];
417 if (applicationName.Length > 256)
418 throw new ProviderException ("The ApplicationName attribute must be 256 characters long or less.");
419 if (connectionStringName == null || connectionStringName.Length == 0)
420 throw new ProviderException ("The ConnectionStringName attribute must be present and non-zero length.");
422 // XXX check connectionStringName and commandTimeout
424 connectionString = WebConfigurationManager.ConnectionStrings[connectionStringName];
427 public override bool IsUserInRole (string username, string rolename)
429 string commandText = @"
431 FROM dbo.aspnet_Users, dbo.aspnet_UsersInRoles, dbo.aspnet_Roles, dbo.aspnet_Applications
432 WHERE dbo.aspnet_Roles.ApplicationId = dbo.aspnet_Applications.ApplicationId
433 AND dbo.aspnet_Users.ApplicationId = dbo.aspnet_Applications.ApplicationId
434 AND dbo.aspnet_UsersInRoles.RoleId = dbo.aspnet_Roles.RoleId
435 AND dbo.aspnet_UsersInRoles.UserId = dbo.aspnet_Users.UserId
436 AND dbo.aspnet_Applications.LoweredApplicationName = LOWER(@ApplicationName)
437 AND dbo.aspnet_Roles.LoweredRoleName = LOWER(@RoleName)
438 AND dbo.aspnet_Users.LoweredUserName = LOWER(@UserName)
442 bool closed = connection.State == ConnectionState.Closed;
446 DbCommand command = factory.CreateCommand ();
447 command.CommandText = commandText;
448 command.Connection = connection;
449 command.CommandType = CommandType.Text;
450 AddParameter (command, "RoleName", rolename);
451 AddParameter (command, "UserName", username);
452 AddParameter (command, "ApplicationName", ApplicationName);
454 bool rv = ((int)command.ExecuteScalar ()) != 0;
462 public override void RemoveUsersFromRoles (string [] usernames, string [] rolenames)
464 string commandText = @"
465 DELETE dbo.aspnet_UsersInRoles
466 FROM dbo.aspnet_UsersInRoles, dbo.aspnet_Users, dbo.aspnet_Roles, dbo.aspnet_Applications
467 WHERE dbo.aspnet_UsersInRoles.UserId = dbo.aspnet_Users.UserId
468 AND dbo.aspnet_UsersInRoles.RoleId = dbo.aspnet_Roles.RoleId
469 AND dbo.aspnet_Roles.ApplicationId = dbo.aspnet_Applications.ApplicationId
470 AND dbo.aspnet_Users.ApplicationId = dbo.aspnet_Applications.ApplicationId
471 AND dbo.aspnet_Users.LoweredUserName = LOWER(@UserName)
472 AND dbo.aspnet_Roles.LoweredRoleName = LOWER(@RoleName)
473 AND dbo.aspnet_Applications.LoweredApplicationName = LOWER(@ApplicationName)";
478 foreach (string u in usernames) {
480 throw new ArgumentNullException ("null element in usernames array");
481 if (h.ContainsKey (u))
482 throw new ArgumentException ("duplicate element in usernames array");
483 if (u.Length == 0 || u.Length > 256 || u.IndexOf (",") != -1)
484 throw new ArgumentException ("element in usernames array in illegal format");
489 foreach (string r in usernames) {
491 throw new ArgumentNullException ("null element in usernames array");
492 if (h.ContainsKey (r))
493 throw new ArgumentException ("duplicate element in usernames array");
494 if (r.Length == 0 || r.Length > 256 || r.IndexOf (",") != -1)
495 throw new ArgumentException ("element in usernames array in illegal format");
501 bool closed = connection.State == ConnectionState.Closed;
505 DbTransaction trans = connection.BeginTransaction ();
508 foreach (string username in usernames) {
509 foreach (string rolename in rolenames) {
510 DbCommand command = factory.CreateCommand ();
511 command.Transaction = trans;
512 command.CommandText = commandText;
513 command.Connection = connection;
514 command.CommandType = CommandType.Text;
515 AddParameter (command, "UserName", username);
516 AddParameter (command, "RoleName", rolename);
517 AddParameter (command, "ApplicationName", ApplicationName);
519 if (command.ExecuteNonQuery() != 1)
520 throw new ProviderException (String.Format ("failed to remove users from role '{0}'.", rolename));
526 catch (Exception e) {
528 if (e is ProviderException)
531 throw new ProviderException ("", e);
539 public override bool RoleExists (string rolename)
541 string commandText = @"
543 FROM dbo.aspnet_Roles, dbo.aspnet_Applications
544 WHERE dbo.aspnet_Roles.ApplicationId = dbo.aspnet_Applications.ApplicationId
545 AND dbo.aspnet_Applications.LoweredApplicationName = LOWER(@ApplicationName)
546 AND dbo.aspnet_Roles.LoweredRoleName = LOWER(@RoleName)
550 bool closed = connection.State == ConnectionState.Closed;
554 DbCommand command = factory.CreateCommand ();
555 command.CommandText = commandText;
556 command.Connection = connection;
557 command.CommandType = CommandType.Text;
558 AddParameter (command, "ApplicationName", ApplicationName);
559 AddParameter (command, "RoleName", rolename);
561 bool rv = ((int)command.ExecuteScalar ()) != 0;
570 public override string ApplicationName {
571 get { return applicationName; }
573 applicationName = value;