Модераторы: gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Проблема с авторизацией клиента в WCF-сервисе 
V
    Опции темы
cha0ss
Дата 15.9.2009, 16:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 21
Регистрация: 8.9.2009

Репутация: нет
Всего: нет



Здравствуйте, возникла необходимость подключения к WCF-сервису не через Windows-аутентификацию. 
Для этого я динамически создаю binding и endpointadress, но не нашел где все таки прописывать имя пользователя и пароль под которым я хочу запустить метод.

Код

                            WSHttpBinding bind = new WSHttpBinding(SecurityMode.Message);
                            EndpointAddress address = new EndpointAddress("http://komp:2222/BDService");
                            BDFunc.bdc = new BDClient(bind, address);
                            BDFunc.bdc.Open();




Это сообщение отредактировал(а) cha0ss - 15.9.2009, 16:28
PM MAIL   Вверх
mihryak
Дата 15.9.2009, 17:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 731
Регистрация: 28.4.2007
Где: С-Пб

Репутация: 3
Всего: 36



ClientCredentials Property
только вот как-то мало ты конфигуришь binding
так как минимум понадобится строка
Код

binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;

PM MAIL ICQ   Вверх
cha0ss
Дата 16.9.2009, 11:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 21
Регистрация: 8.9.2009

Репутация: нет
Всего: нет



Код

                            //Создаем binding
                            WSHttpBinding bind = new WSHttpBinding(SecurityMode.Message);
                            bind.Security.Message.ClientCredentialType = MessageCredentialType.UserName;

                            //Создаем endpoint
                            EndpointIdentity identity = EndpointIdentity.CreateDnsIdentity("localhost");
                            EndpointAddress address = new EndpointAddress(new Uri("http://komp:2222/BDService"), identity, (System.ServiceModel.Channels.AddressHeaderCollection)null);

                            BDFunc.bdc = new BDClient(bind, address);
                            bdc.ClientCredentials.UserName.UserName = "login";
                            bdc.ClientCredentials.UserName.Password = "pass";
                            BDFunc.bdc.Open();


при открытии соединения получаю следующую ошибку:
{"Не удалось открыть безопасный канал, так как произошла ошибка при согласовании безопасности с удаленной стороной. Возможно, это связано с отсутствием или неправильным указанием EndpointIdentity в EndpointAddress, использованном для создания канала. Убедитесь, что EndpointIdentity, указанный или подразумеваемый в EndpointAddress, правильно идентифицирует удаленную сторону. "}

пытался менять CreateDnsIdentity на CreateUpnIdentity, не помогает - в ответ все таже ошибка.
PM MAIL   Вверх
mihryak
Дата 21.9.2009, 15:52 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 731
Регистрация: 28.4.2007
Где: С-Пб

Репутация: 3
Всего: 36



я не опоздал? smile
впрочем, кому-нибудь ещё может пригодиться пример self-hosted wcf service'а с юзернеймовой аутентификацией, с кастомным юзерским валидатором, без сертификатов и ssl (транспортная секьюрность и секьюрность сообщений отключена), сконфиругированный кодом, а не app.config'ом (вроде бы, не забыл ничего smile)
итак, сам сервис (обычно в отдельной общей сборке)
Код

    [ServiceContract]
    public interface IService
    {
        [OperationContract]
        string GetData(int value);
    }

его реализация (в самом host application)
Код

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class Service : IService
    {
        public string GetData(int value)
        {
            return value.ToString();
        }
    }

валидатор пользователей (там же)
Код

    class UserNameValidator : UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            if (userName != "user" ||
                password != "password")
            {
                throw new SecurityTokenException("Authentication failed");
            }
        }
    }

prorgam.cs host application'а
Код

        static void Main()
        {
            Console.WriteLine("Starting...");

            Service service = new Service();
            Uri address = new Uri("http://localhost:5556/WcfClient/Service/");
            using (ServiceHost host = new ServiceHost(service, address))
            {
                WSHttpBinding binding = new WSHttpBinding(SecurityMode.None);
                binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
                binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
                host.AddServiceEndpoint(typeof (IService), binding, address);

                host.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
                host.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new UserNameValidator();

                host.Open();

                Console.WriteLine("Started");
                Console.WriteLine("Press any key to quit...");
                Console.ReadKey();
            }
        }

program.cs client apllication'а
Код

        static void Main(string[] args)
        {
            Console.WriteLine("Press any key to call service...");
            Console.ReadKey();

            WSHttpBinding binding = new WSHttpBinding(SecurityMode.None);
            binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
            binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
            EndpointAddress address = new EndpointAddress("http://localhost:5556/WcfClient/Service/");
            using (var factory = new ChannelFactory<IService>(binding, address))
            {
                factory.Credentials.UserName.UserName = "username";
                factory.Credentials.UserName.Password = "password";
                IService service = factory.CreateChannel();
                Console.WriteLine("Service response: {0}", service.GetData(25));
            }

            Console.WriteLine("Press any key to quit...");
            Console.ReadKey();
        }

PM MAIL ICQ   Вверх
cha0ss
Дата 22.9.2009, 09:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 21
Регистрация: 8.9.2009

Репутация: нет
Всего: нет



Спасибо, это обязательно пригодится!
Я сделал по другому, в моей программе оказалось достаточным Windows-аутентификации под текущим пользователем + возможность ввести другие логин / пароль (но также под Windows-аутентификацией).
PM MAIL   Вверх
v_enom
Дата 24.9.2009, 00:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 101
Регистрация: 11.10.2006

Репутация: нет
Всего: нет



mihryak
покажи пожалуйста, как проверяешь на сервере, правильность пароля и имени (например из базы с пользователями на сервере берешь)....
я понимаю что функцией  void Validate(string userName, string password)
но где она вызывается? или она как-то по-особому работает, что сама все делает??? в общем где она проявляется на серваке, опиши, а?
и кто возвращает ошибку, в случае неверной валидации????

и немного не понятна эта запись 
 
Код

host.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new UserNameValidator();

где она вызывается? (я создаю wcf сервер через окна IDE ).
у меня есть файлы WcfUploaderIService.cs(с контрактами) и WcfUploaderService.cs (с кодом)
где писать все это добро
Код


 host.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
                host.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new UserNameValidator();




и еще... а как на практике реализуется открытие части функций с помощью 
Код

[PrincipalPermission(SecurityAction.Demand, Name @"MAxhineName\гость")]


т.е. что надо выставить/прописать в client application (а может еще и в конфиге и сервере), чтобы все, кто не авторизовались по валидации все же могла что-то там делать....например только "смотреть таблицу из бд"
и т.д.


Это сообщение отредактировал(а) v_enom - 24.9.2009, 00:44
PM MAIL   Вверх
mihryak
Дата 24.9.2009, 16:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 731
Регистрация: 28.4.2007
Где: С-Пб

Репутация: 3
Всего: 36



Цитата(v_enom @  24.9.2009,  01:33 Найти цитируемый пост)
покажи пожалуйста, как проверяешь на сервере, правильность пароля и имени (например из базы с пользователями на сервере берешь)....
я понимаю что функцией  void Validate(string userName, string password)
но где она вызывается? или она как-то по-особому работает, что сама все делает??? в общем где она проявляется на серваке, опиши, а?
и кто возвращает ошибку, в случае неверной валидации????

Првильность проверяется на усмотрение пишущего кастомный валидатор (база данных, другой аутентификационный сервис и т.д.). Если креды плохие, то этот метод должен выкинуть SecurityTokenException.
Для использования кастомного валидатора нужно указать, что предполагается его использование
Код

host.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;

и задать сам экземпляр валидатора
Код

host.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new UserNameValidator();

Сам метод класса вызывается автоматически инфраструктурой WCF, всё что требуется - просто его указать

Вообще, кастомные валидаторы не рекомендуются, см. здесь, лучше прикрутить MembershipProvider

Цитата(v_enom @  24.9.2009,  01:33 Найти цитируемый пост)
где писать все это добро

Зависит от того, так ты стартуешь сервис, кто его хостит. Если как у меня (self-hosted wcf service) - то либо в prorgam.cs прописать мой код, либо в app.config, а если хостит IIS, то, насколько знаю, только конфигом

Цитата(v_enom @  24.9.2009,  01:33 Найти цитируемый пост)
и еще... а как на практике реализуется открытие части функций с помощью 
[PrincipalPermission(SecurityAction.Demand, Name @"MAxhineName\гость")]

Это уже относится не к аутентификации (принятие или непринятие пользователя), а к авторизации (раздача уже принятому пользователю его прав). См. всё ту же ссылку с best practices.
Для кастомной проверки ролей (не рекомендуется)
1. пометить метод атрибутом
Код

        [PrincipalPermission(SecurityAction.Demand, Role = "guest")]
        public string GetData(int value)
        {
            return value.ToString();
        }

2. сделать ещё один класс-валидатор
Код

    public class AuthorizationPolicy : IAuthorizationPolicy
    {
        private readonly string _id = Guid.NewGuid().ToString();
        public string Id
        {
            get { return _id; }
        }
        public bool Evaluate(EvaluationContext evaluationContext, ref object state)
        {
            if (evaluationContext.Properties.ContainsKey("Identities"))
            {
                IList<IIdentity> identities =
                    evaluationContext.Properties["Identities"] as IList<IIdentity>;
                if (identities != null && identities.Count > 0)
                {
                    evaluationContext.Properties["Principal"] = new CustomPrincipal(identities[0]);
                    return true;
                }
            }
            return false;
        }
        public ClaimSet Issuer
        {
            get { return ClaimSet.System; }
        }
        private class CustomPrincipal : IPrincipal
        {
            private readonly IIdentity _identity;
            public CustomPrincipal(IIdentity identity)
            {
                _identity = identity;
            }
            public IIdentity Identity
            {
                get { return _identity; }
            }
            public bool IsInRole(string role)
            {
                return CheckIdentityRole(Identity, role);
            }
        }
    }

3. сконфигурить хост, указав, что надо использовать его
Код

                host.Authorization.PrincipalPermissionMode = PrincipalPermissionMode.Custom;
                host.Authorization.ExternalAuthorizationPolicies =
                    new ReadOnlyCollection<IAuthorizationPolicy>(
                        new List<IAuthorizationPolicy> {new AuthorizationPolicy()});


Каждый частный случай реализации аутентификации-авторизации требует отдельного рассмотрения, то, что у меня - лишь демо-пример, причём не лучший
PM MAIL ICQ   Вверх
v_enom
Дата 24.9.2009, 20:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 101
Регистрация: 11.10.2006

Репутация: нет
Всего: нет



mihryak
спасибо, поковыряв твои примеры и книги можно уже разобраться, как сделать валидацию...
PM MAIL   Вверх
NikeDeForest
Дата 15.10.2009, 07:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 136
Регистрация: 15.9.2007

Репутация: нет
Всего: 2



А почему проверка ролей не рекомендуется? И что рекомендуется тогда, заявки (claims)?
--------------------
Еще один вопрос ...
PM   Вверх
anikss
Дата 10.11.2009, 22:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 5
Регистрация: 8.11.2005
Где: Москва

Репутация: нет
Всего: нет



Цитата(mihryak @  21.9.2009,  15:52 Найти цитируемый пост)
я не опоздал? 
впрочем, кому-нибудь ещё может пригодиться пример self-hosted wcf service'а с юзернеймовой аутентификацией, с кастомным юзерским валидатором, без сертификатов и ssl (транспортная секьюрность и секьюрность сообщений отключена), сконфиругированный кодом, а не app.config'ом (вроде бы, не забыл ничего )


Здравствуйте! Проверил ваш пример, проверка пароля не производитс, и при указании неправильного пароля операция все равно выполняется.
Подскажите пожалуйста, как же все-таки сделать аутентификацию по логину и паролю без сертификата?
PM MAIL WWW ICQ   Вверх
EagleOne
Дата 27.11.2009, 21:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 43
Регистрация: 20.11.2009

Репутация: нет
Всего: 1



Цитата

Здравствуйте! Проверил ваш пример, проверка пароля не производитс, и при указании неправильного пароля операция все равно выполняется.
Подскажите пожалуйста, как же все-таки сделать аутентификацию по логину и паролю без сертификата?


1. Ага, не производится, потому что в приведенном примере контекст безопасности не будет содержать идентификационной информации....

Цитата

как же все-таки сделать аутентификацию по логину и паролю без сертификата


Можно в коде приведенном выше заменить

Код

binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;


на

Код

binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;


Вот тогда идентификационная информацию уйдет в http. В этом случае при неправильном логине или пароле будет вываливаться, что 
HTTP запросы запрещены для данной схемы проверки подлинности... 


Цитата

операция все равно выполняется


2. Так чё бы ей не выполняться то... Аутентификация это не авторизация... А чтобы определять выполняться для определенного пользователя
тот или иной метод, нужно писать авторизацию на основе ролей или заявок... 
-------------------------------------------------------------------------------------------------------------------

А теперь собсно мой вопрос к гуру WCF-а и безопасности в нем smile

У меня случай такой:
Пользователи на мой WCF-сервис попадают через инет по логину и паролю (т.е. все что должно требоваться от пользвателя  это тока знание логина и пароля...).
Данные должны шифроваться - т.е. пользователь через http аналайзер не должен увидеть ни данных, ни логина и пароля... 
Авторизация должна быть на основе ролей.... Использовать поставщика ролей ASP.NET никакой возможности нет Кастомный провайдер ролей писать тоже очень не
желательно... 

Т.е. основной преемлимый вариант - писать кастомные методы для сопоставления пользователя ролям (с этим кстате проблем нет).

Проблема в том как передать идентификационную информацию сервису  - в UserNameValidator, причем так чтоб её другие не сперли... Какую привязку лучше для
этого использовать, как её конфигурировать, как сделать шифрование... ?
Смотрел уже и MSDN и в других источниках... - информация преподнесена ацтой как (это я про MSDN и про ReMIX), да ещё и в примерах ошибки...    :(

 

Это сообщение отредактировал(а) EagleOne - 27.11.2009, 22:02
PM MAIL   Вверх
Medic
Дата 1.3.2010, 06:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 9
Регистрация: 6.6.2005

Репутация: нет
Всего: нет



А как можно UserName/Password авторизацию реализовать при basicHttpBinding (SilverLight только его поддерживает)?
WCF сервис хостится вне IIS.

Это сообщение отредактировал(а) Medic - 1.3.2010, 06:12
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
cully
mr.DUDA
Exception

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, cully, mr.DUDA, Exception.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Распределённые приложения и сеть | Следующая тема »


 




[ Время генерации скрипта: 0.1102 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.