カスタム アイデンティティ ストアのユーザーとロールを使用して ArcGIS Server のセキュリティを強化できます。
備考:
カスタム アイデンティティ ストアは 10.7 で廃止になりました。推奨されるセキュリティ構成については、「ArcGIS Server でのアクセスと認証」をご参照ください。
このために、ArcGIS Server では ASP.NET メンバーシップ プロバイダーおよびロール プロバイダーがサポートされています。
ASP.NET を使用してカスタム アイデンティティ ストアを構成する主な手順は、次のとおりです。
- ArcGIS Server に対応した ASP.NET カスタム プロバイダーを実装します。
備考:
ASP.NET カスタム プロバイダーでは、.NET Framework 4.5.1 以降を使用する必要があります。
 - カスタム プロバイダーを ArcGIS Server に配置します。
 - カスタム プロバイダーを使用するように ArcGIS Server を構成します。
 
カスタム ASP.NET プロバイダーを構成したら、Manager でコンテンツを表示し、カスタム ストアにあるロールを使用して Web サービスの権限を設定できます。
ArcGIS Server に対応した ASP.NET カスタム プロバイダーの実装
カスタム アイデンティティ ストアのユーザーを使用して ArcGIS Server のセキュリティを強化する場合は、次のメソッドを実装する ASP.NET メンバーシップ プロバイダーを開発する必要があります。
- FindUsersByName
 - GetAllUsers
 - GetUser
 - ValidateUser
 
カスタム アイデンティティ ストアのロールを使用して ArcGIS Server のセキュリティを強化する場合は、次のメソッドを実装する 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 Server 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>