ASP.NET を使用したカスタム アイデンティティ ストアの設定
このトピックの内容
- ArcGIS Server 用の ASP.NET カスタム プロバイダーの実装
- カスタム プロバイダーの ArcGIS Server への配置
- カスタム プロバイダーを使用するための ArcGIS Server の構成
- 実装サンプル
カスタム アイデンティティ ストアのユーザーとロールによって ArcGIS Server のセキュリティを強化できます。このために、ArcGIS Server では ASP.NET メンバーシップとロール プロバイダーがサポートされています。
ASP.NET を使用してカスタム アイデンティティ ストアを構成するには、次の手順に従います。
カスタム ASP.NET プロバイダーを構成したら、Manager でコンテンツを表示し、カスタム ストアにあるロールを使用して Web サービスの権限を設定できます。
ArcGIS Server 用の ASP.NET カスタム プロバイダーの実装
カスタム アイデンティティ ストアのユーザーを使用して ArcGIS Server をセキュリティで保護するには、次のメソッドを実装する .NET Framework 3.5 ASP.NET メンバーシップ プロバイダーを開発する必要があります。
- FindUsersByName
- GetAllUsers
- GetUser
- ValidateUser
カスタム アイデンティティ ストアのロールを使用して ArcGIS Server をセキュリティで保護するには、次のメソッドを実装する .NET Framework 3.5 ASP.NET ロール プロバイダーを開発する必要があります。
- GetAllRoles
- GetRolesForUser
- GetUsersInRole
注意:
ASP.NET カスタム プロバイダーを実装する場合、それを読み取り専用アイデンティティ ストアとして ArcGIS Server で公開することをお勧めします。ArcGIS Server を通じてユーザー/ロールの情報を作成および変更する場合、ASP.NET カスタム プロバイダーで、下の実装サンプルに示されている追加メソッドを実装する必要があります。
カスタム プロバイダーの ArcGIS Server への配置
- カスタム プロバイダーを *.dll ファイル内に構築し、ArcGIS Server をホストしているコンピューターにコピーします。
- カスタム プロバイダー .dll を GAC 内にインストールします。
例: gacutil /i MyCustomProvider.dll
カスタム プロバイダーを使用するための ArcGIS Server の構成
カスタム ASP.NET プロバイダーを使用するように ArcGIS Server を設定するには、ASP.NET プロバイダーの type 属性を指定する必要があります。必要に応じて、プロバイダーで必要となるランタイム プロパティ (ユーザーの認証情報など) を指定することもできます。
- ArcGIS Sever Administrator Directory を開いて、ログインします。
- [security] > [config] > [updateIdentityStore] の順にクリックします。
- User Store の構成を JSON 形式で入力します。構文は次のようになります。
{ "type": "ASP_NET", "class": "{Membership provider's type attribute value}", "properties": { "Property One": "value", .... "Property X": "value" } }
- Role Store の構成を JSON 形式で入力します。構文は次のようになります。
{ "type": "ASP_NET", "class": "{Role provider's type attribute value}", "properties": { "Property One": "value", .... "Property X": "value" } }
- [update] をクリックして構成を保存します。
実装サンプル
C# での ArcGIS Server 用の ASP.NET メンバーシップ プロバイダーおよびロール プロバイダーの実装サンプルを次に示します。このサンプルでは、変更可能な ASP .NET プロバイダーを使用しています。プロバイダーを、読み取り専用アイデンティティ ストアとして ArcGIS Server で公開することをお勧めします。
メンバーシップ プロバイダーのサンプル
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration.Provider;
using System.Linq;
using System.Text;
using System.Web.Security;
using System.Web.Hosting;
using System.Web.Management;
using System.Web;
using System.Security.Permissions;
using System.Xml;
using System.IO;
namespace CustomProvider
{
public class XmlMembershipProvider : MembershipProvider
{
private string _appName = null;
private string _providerName = null;
private string _userStore;
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
if (config == null)
throw new ArgumentNullException("config");
if (String.IsNullOrEmpty(name))
name = "CustomProvider.XmlMembershipProvider";
base.Initialize(name, config);
_providerName = name;
string path = config["FileName"];
if (String.IsNullOrEmpty(path))
path = "C:\\temp\\IdentityStore.xml";
else
_userStore = path;
FileIOPermission permission = new FileIOPermission(FileIOPermissionAccess.Write,_userStore);
permission.Demand();
}
public override string ApplicationName
{
get
{
return _appName;
}
set
{
_appName = value;
}
}
public override bool ChangePassword(string username, string oldPassword, string newPassword)
{
throw new NotImplementedException();
}
public override bool ChangePasswordQuestionAndAnswer(string username, string password, string newPasswordQuestion, string newPasswordAnswer)
{
return true;
}
public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status)
{
MembershipUser newUser = new MembershipUser(
_providerName,
username,
null,
email,
"Secret Question",
username,
true,
false,
DateTime.Now, // creationDate
DateTime.Now, // lastLoginDate
DateTime.Now, // lastActivityDate
DateTime.Now, // lastPasswordChangedDate
new DateTime(2000, 1, 1) // lastLockoutDate
);
XmlDocument _usersList = ReadUsersFromStore();
XmlNode newUserNode = _usersList.CreateNode(XmlNodeType.Element, "User", null);
XmlNode newUserInfoNode = _usersList.CreateElement("UserName");
newUserInfoNode.InnerText = username;
newUserNode.AppendChild(newUserInfoNode);
newUserInfoNode = _usersList.CreateElement("Password");
newUserInfoNode.InnerText = password;
newUserNode.AppendChild(newUserInfoNode);
newUserInfoNode = _usersList.CreateElement("FullName");
newUserInfoNode.InnerText = username;
newUserNode.AppendChild(newUserInfoNode);
newUserInfoNode = _usersList.CreateElement("Email");
newUserInfoNode.InnerText = email;
newUserNode.AppendChild(newUserInfoNode);
newUserInfoNode = _usersList.CreateElement("Roles");
newUserNode.AppendChild(newUserInfoNode);
_usersList.DocumentElement.AppendChild(newUserNode);
_usersList.Save(_userStore);
status = MembershipCreateStatus.Success;
return newUser;
}
public override bool DeleteUser(string username, bool deleteAllRelatedData)
{
XmlDocument _usersList = ReadUsersFromStore();
XmlNode nodeToDelete = _usersList.SelectSingleNode(string.Format("//*[UserName=\"{0}\"]", username));
if (nodeToDelete != null)
{
_usersList.FirstChild.RemoveChild(nodeToDelete);
_usersList.Save(_userStore);
return true;
}
else
return false;
}
public override bool EnablePasswordReset
{
get { return true; }
}
public override bool EnablePasswordRetrieval
{
get { return true; }
}
public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
{
throw new NotImplementedException();
}
public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
{
MembershipUserCollection usersColl = new MembershipUserCollection();
XmlNodeList matchingNodes = null;
XmlDocument _usersList = ReadUsersFromStore();
matchingNodes = _usersList.SelectNodes(string.Format("//*[contains(UserName,\"{0}\")]", usernameToMatch));
totalRecords = 0;
if (matchingNodes != null && matchingNodes.Count != 0)
{
totalRecords = matchingNodes.Count;
foreach (XmlNode node in matchingNodes)
{
MembershipUser newUser = new MembershipUser(
_providerName,
node["UserName"].InnerText,
null,
node["Email"].InnerText,
"",
node["UserName"].InnerText,
true,
false,
DateTime.Now, // creationDate
DateTime.Now, // lastLoginDate
DateTime.Now, // lastActivityDate
DateTime.Now, // lastPasswordChangedDate
new DateTime(2000, 1, 1) // lastLockoutDate
);
usersColl.Add(newUser);
}
}
return usersColl;
}
public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
{
MembershipUserCollection usersColl = new MembershipUserCollection();
XmlDocument _usersList = ReadUsersFromStore();
XmlNodeList userNodes = _usersList.GetElementsByTagName("User");
foreach (XmlNode node in userNodes)
{
MembershipUser newUser = new MembershipUser(
_providerName,
node["UserName"].InnerText,
null,
node["Email"].InnerText,
"Secret Question",
node["UserName"].InnerText,
true,
false,
DateTime.Now, // creationDate
DateTime.Now, // lastLoginDate
DateTime.Now, // lastActivityDate
DateTime.Now, // lastPasswordChangedDate
new DateTime(2000, 1, 1) // lastLockoutDate
);
usersColl.Add(newUser);
}
totalRecords = userNodes.Count;
return usersColl;
}
public override int GetNumberOfUsersOnline()
{
throw new NotImplementedException();
}
public override string GetPassword(string username, string answer)
{
throw new NotImplementedException();
}
public override MembershipUser GetUser(string username, bool userIsOnline)
{
XmlDocument _usersList = ReadUsersFromStore();
MembershipUser user = null;
XmlNode node = _usersList.SelectSingleNode(string.Format("//*[UserName=\"{0}\"]", username));
if (node != null)
{
user = new MembershipUser(
_providerName,
node["UserName"].InnerText,
null,
node["Email"].InnerText,
"Secret Question",
node["UserName"].InnerText,
true,
false,
DateTime.Now, // creationDate
DateTime.Now, // lastLoginDate
DateTime.Now, // lastActivityDate
DateTime.Now, // lastPasswordChangedDate
new DateTime(2000, 1, 1) // lastLockoutDate
);
}
return user;
}
public override MembershipUser GetUser(object providerUserKey, bool userIsOnline)
{
throw new NotImplementedException();
}
public override string GetUserNameByEmail(string email)
{
throw new NotImplementedException();
}
public override int MaxInvalidPasswordAttempts
{
get { throw new NotImplementedException(); }
}
public override int MinRequiredNonAlphanumericCharacters
{
get { throw new NotImplementedException(); }
}
public override int MinRequiredPasswordLength
{
get { throw new NotImplementedException(); }
}
public override int PasswordAttemptWindow
{
get { throw new NotImplementedException(); }
}
public override MembershipPasswordFormat PasswordFormat
{
get { throw new NotImplementedException(); }
}
public override string PasswordStrengthRegularExpression
{
get { throw new NotImplementedException(); }
}
public override bool RequiresQuestionAndAnswer
{
get { throw new NotImplementedException(); }
}
public override bool RequiresUniqueEmail
{
get { throw new NotImplementedException(); }
}
public override string ResetPassword(string username, string answer)
{
throw new NotImplementedException();
}
public override bool UnlockUser(string userName)
{
throw new NotImplementedException();
}
public override void UpdateUser(MembershipUser user)
{
XmlDocument _usersList = ReadUsersFromStore();
String username = user.UserName;
XmlNode nodeToUpdate = _usersList.SelectSingleNode(string.Format("//*[UserName=\"{0}\"]", username));
if (nodeToUpdate != null)
{
nodeToUpdate["Email"].InnerText = user.Email;
_usersList.Save(_userStore);
}
}
public override bool ValidateUser(string username, string password)
{
XmlDocument _usersList = ReadUsersFromStore();
XmlNode node = _usersList.SelectSingleNode(string.Format("//*[UserName=\"{0}\"]", username));
if (node != null && username.Equals(node["UserName"].InnerText) && password.Equals(node["Password"].InnerText))
return true;
else
return false;
}
private XmlDocument ReadUsersFromStore()
{
XmlDocument _usersList = new XmlDocument();
_usersList.Load(_userStore);
return _usersList;
}
} /* XmlFileMembershipProvider */
}
ロール プロバイダーのサンプル
using System;
using System.Collections.Generic;
using System.Collections;
using System.Collections.Specialized;
using System.Configuration.Provider;
using System.Linq;
using System.Text;
using System.Web.Security;
using System.Web.Hosting;
using System.Web.Management;
using System.Web;
using System.Security.Permissions;
using System.Xml;
using System.IO;
namespace CustomProvider
{
public class XmlRoleProvider : RoleProvider
{
private string _appName = null;
private string _providerName = null;
private string _roleStore = null;
XmlDocument _xmlRoleList = null;
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
if (config == null)
throw new ArgumentNullException("config");
if (String.IsNullOrEmpty(name))
name = "CustomProvider.XmlRoleProvider";
base.Initialize(name, config);
_providerName = name;
string path = config["FileName"];
if (String.IsNullOrEmpty(path))
path = "C:\\temp\\IdentityStore.xml";
else
_roleStore = path;
FileIOPermission permission = new FileIOPermission(FileIOPermissionAccess.Write, _roleStore);
permission.Demand();
}
public override void AddUsersToRoles(string[] usernames, string[] roleNames)
{
XmlDocument userRoleDoc = ReadUserRolesFromStore();
foreach (string user in usernames)
{
XmlNode userRoleNode = userRoleDoc.SelectSingleNode(string.Format("//*[UserName=\"{0}\"]", user));
String roleList = userRoleNode["Roles"].InnerText;
foreach (string role in roleNames)
{
if(roleList.Equals(""))
roleList += role;
else
roleList += "," + role;
}
userRoleNode.RemoveChild(userRoleNode.LastChild);
XmlNode newRoleListNode = userRoleDoc.CreateElement("Roles");
newRoleListNode.InnerText = roleList;
userRoleNode.AppendChild(newRoleListNode);
}
userRoleDoc.Save(_roleStore);
}
public override string ApplicationName
{
get
{
return _appName;
}
set
{
_appName = value;
}
}
public override void CreateRole(string roleName)
{
ReadRolesFromStore();
XmlNode newRoleNode = _xmlRoleList.CreateNode(XmlNodeType.Element, "Role", null);
XmlNode newUserInfoNode = _xmlRoleList.CreateElement("RoleName");
newUserInfoNode.InnerText = roleName;
newRoleNode.AppendChild(newUserInfoNode);
_xmlRoleList.DocumentElement.AppendChild(newRoleNode);
_xmlRoleList.Save(_roleStore);
}
public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
{
ReadRolesFromStore();
XmlNode nodeToDelete = _xmlRoleList.SelectSingleNode(string.Format("//*[RoleName=\"{0}\"]", roleName));
if (nodeToDelete != null)
{
_xmlRoleList.FirstChild.RemoveChild(nodeToDelete);
_xmlRoleList.Save(_roleStore);
return true;
}
else
return false;
}
public override string[] FindUsersInRole(string roleName, string usernameToMatch)
{
throw new NotImplementedException();
}
public override string[] GetAllRoles()
{
ArrayList roleArrayList = ReadRolesFromStore();
return (string[])roleArrayList.ToArray(typeof(string));
}
public override string[] GetRolesForUser(string username)
{
XmlDocument xmlUserRolesList = ReadUserRolesFromStore();
XmlNode userRoleNode = xmlUserRolesList.SelectSingleNode(string.Format("//*[UserName=\"{0}\"]", username));
String[] roleList = userRoleNode["Roles"].InnerText.Split(',');
if (roleList[0] == "")
return new string[0];
else
return roleList;
}
public override string[] GetUsersInRole(string roleName)
{
ArrayList userList = new ArrayList();
XmlDocument xmlUserRolesList = ReadUserRolesFromStore();
XmlNodeList userRoleNodes = xmlUserRolesList.GetElementsByTagName("User");
if (userRoleNodes != null)
{
int numRoles = userRoleNodes.Count;
foreach(XmlNode node in userRoleNodes) {
String[] roleList = node["Roles"].InnerText.Split(',');
foreach (string item in roleList)
{
if (item.Equals(roleName))
{
String username = node["UserName"].InnerText;
userList.Add(username);
break;
}
}
}
}
return (string[])userList.ToArray(typeof(string));
}
public override bool IsUserInRole(string username, string roleName)
{
throw new NotImplementedException();
}
public override void RemoveUsersFromRoles(string[] usernames, string[] roleNames)
{
XmlDocument userRoleDoc = ReadUserRolesFromStore();
foreach (string user in usernames)
{
XmlNode userRoleNode = userRoleDoc.SelectSingleNode(string.Format("//*[UserName=\"{0}\"]", user));
ArrayList roleList = new ArrayList();
roleList.AddRange(userRoleNode["Roles"].InnerText.Split(','));
foreach (string role in roleNames)
{
if (roleList.Contains(role))
roleList.Remove(role);
}
userRoleNode.RemoveChild(userRoleNode.LastChild);
XmlNode newRoleListNode = userRoleDoc.CreateElement("Roles");
if( roleList.Count > 0 )
newRoleListNode.InnerText = string.Join(",", (string[])roleList.ToArray(Type.GetType("System.String")));
userRoleNode.AppendChild(newRoleListNode);
}
userRoleDoc.Save(_roleStore);
}
public override bool RoleExists(string roleName)
{
throw new NotImplementedException();
}
private ArrayList ReadRolesFromStore()
{
_xmlRoleList = new XmlDocument();
_xmlRoleList.Load(_roleStore);
XmlNodeList roleNodes = _xmlRoleList.GetElementsByTagName("Role");
ArrayList roleArrayList = null;
if (roleNodes != null)
{
roleArrayList = new ArrayList();
foreach (XmlNode node in roleNodes)
{
roleArrayList.Add( node["RoleName"].InnerText);
}
}
return roleArrayList;
}
private XmlDocument ReadUserRolesFromStore()
{
XmlDocument xmlUserRolesList = new XmlDocument();
xmlUserRolesList.Load(_roleStore);
return xmlUserRolesList;
}
}
}
アイデンティティ ストア構成 JSON のサンプル
ユーザー ストア JSON
{
"type": "ASP_NET",
"class": "CustomProvider.XmlMembershipProvider,CustomProvider,Version=1.0.0.0,Culture=Neutral,PublicKeyToken=b02390eb7f2c02c4",
"properties": {
"FileName": "C:\\arcgisserver\\identitystore\\IdentityStore.xml"
}
}
ロール ストア JSON
{
"type": "ASP_NET",
"class": "CustomProvider.XmlRoleProvider,CustomProvider,Version=1.0.0.0,Culture=Neutral,PublicKeyToken=b02390eb7f2c02c4",
"properties": {
"FileName": "C:\\arcgisserver\\identitystore\\IdentityStore.xml"
}
}
アイデンティティ ストアのサンプル
<IdentityStore>
<User>
<UserName>amy</UserName>
<Password>amy</Password>
<FullName>amy</FullName>
<Email>amy@amy.amy</Email>
<Roles>admins</Roles>
</User>
<Role>
<RoleName>admins</RoleName>
</Role>
</IdentityStore>