Logo    
Деловая газета CitCity.ru CITKIT.ru - все об Open Source Форумы Все публикации Учебный центр Курилка
CitForum    CITForum на CD    Подписка на новости портала Море(!) аналитической информации! :: CITFORUM.RU
IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

18.01.2017

Google
WWW CITForum.ru
С Новым годом!

2004 г.

Аутентификация и авторизация пользователей между Web-сервером и сервером приложения в .NET

Шеломанов Роман
www.gotdotnet.ru

В статье рассматривается пример решения задачи по аутентификации и авторизации клиентов Web-сервера на сервере приложения, где под Web-сервером понимается работающее на нем приложение ASP.NET, а под сервером приложения – .NET-приложение. Взаимодействие осуществляется через .NET Remoting (TCP/Binary).

Исходные тексты:

http://www.gotdotnet.com/Community/UserSamples/Details.aspx?SampleGuid=DA54BDF3-B29C-41CB-9517-60705D156D18

В статье рассматривается пример решения задачи по аутентификации и авторизации клиентов Web-сервера на сервере приложения, где под Web-сервером понимается работающее на нем приложение ASP.NET, а под сервером приложения - .NET-приложение. Взаимодействие осуществляется через .NET Remoting (TCP/Binary).

Что есть интересного в рассматриваемом решении:

  • Использование серверных и клиентских специализированных канальных приемников.
  • Организация сессий на стороне сервера приложения и стороне Web-сервера
  • Установление зависимости между клиентом и его сессиями на Web-сервере и сервере приложения.
  • Организация авторизации без добавления дополнительных аргументов в методы сервера приложения.
  • "Протаскивание" пользовательских данных через все методы в потоке без добавления дополнительных аргументов в методы.

В статье не рассматриваются вопросы, связанные с защитой канала передачи данных. О шифровании трафика можно прочитать тут: http://msdn.microsoft.com/msdnmag/issues/03/06/netremoting/

Задача

Архитектура использования

На рисунке 1 изображена схема некоторой информационной системы (ИС)

ИС состоит из ядра - совокупности серверов приложений, выполняющих бизнес-логику, и Web-интерфейса, расположенного на WEB сервере и предоставляющего доступ к системе через Интернет. В приведенной архитектуре и будет использоваться рассматриваемое решение.

Рисунок 1.

Требования
  1. Web-сервер не должен иметь прямого доступа к ИС.
  2. ИСдолжна определять права пользователей на выполнение того или иного запроса (авторизованные и анонимные запросы).
  3. Права пользователей определяются их ролью в ИС.
Дополнительные ограничения

Все сервисы ИС реализованы на базе платформы MS Windows (не ниже MS Windows 2000).

Серверы приложений системы расположены в пределах одной локальной сети.

Решение

Архитектура решения

В соответствии с требованиями разрабатываем архитектуру, представленную на рисунке 2

Рисунок 2.

Web-сервер - предоставляет доступ к ИС через Интернет посредством Web-интерфейса, который реализуется на технологии ASP.NET.

Сервер приложения для WEB - аутентифицирует пользователей, авторизует запросы пользователей, маршрутизирует запросы от Web-сервера к серверам ИС. Реализуются в виде .NET-приложения с возможностью удаленного вызова его методов.

База данных системы - хранит данные ИС.

Серверы приложений системы - совокупность сервисов, реализующих бизнес-логику ИС.

Firewall 1,2 - шлюзы, защищающие ИС от несанкционированного доступа.

Протоколы взаимодействия

На рисунке 3 изображена схема взаимодействия компонентов ИС и протоколы взаимодействия.

Рисунок 3

Интересующий нас участок цепи: Web-сервер - сервер приложения для Web. Мной выбран протокол взаимодействия .NET Remoting через TCP с бинарной сериализацией по причине высокой эффективности этого сочетания по сравнению с HTTP вместе с SOAP.

Идея решения

Идея решения состоит в реализации аутентификации на уровне канальных приемников (ChannelSink), встраиваемых в инфраструктуру канала Remoting на стороне клиента и сервера. Аутентификационная информация передается в заголовках запроса (TransportHeaders), результаты аутентификации передаются в заголовках ответа сервера. Авторизация выполняется с помощью декларативной проверки соответствия роли пользователя.

В случае успешной аутентификации на сервере приложения создается пользовательская сессия, в которой сохраняются пользовательские данные. Другая пользовательская сессия создается на Web-сервере, причем стандартный механизм сессий ASP.NET не используется, поэтому его можно отключить в web.config.

Сессии на сервере приложения и Web-сервере различны по содержанию, так как сервер приложения может хранить обязательные для каждого пользователя объекты, вполне возможно unmanaged (COM). Взаимосвязь между клиентом, Web-сервером и сервером приложения осуществляется по идентификатору сессии.

Развертывание

На рисунке 4 приведена диаграмма развертывания рассматриваемого решения.

Рисунок 4

Решение состоит из трех основных .NET-сборок, обеспечивающих процессы аутентификации, авторизации, поддержку сессий:

SecurityBase - сборка, содержащая общие для Web-сервера и сервера приложения типы и константы.

SecurityClient - сборка, содержащая типы для клиентской части схемы аутентификации и типы, обеспечивающие поддержку сессий на Web-сервере. Устанавливается на Web-сервер.

SecurityServer - сборка, содержащая типы для аутентификации и поддержки сессий на стороне сервера приложения.

Также в пример входит сборка BusinessFacade, содержащая типы, обеспечивающие интерфейс с сервером приложения. На Web-сервер устанавливается сокращенная версия этой сборки, в ней содержатся только сигнатуры методов, без содержания.

На сервере приложения устанавливается полная версия BusinessFacade.

На Web-сервере и сервере приложения настраивается конфигурация Remoting.

На Web-сервере конфигурация содержится в Web.config


<system.runtime.remoting>
  <application name="SHR">
    <client>
      <wellknown type="RemotingExample.BusinessFacade.SomeSystem,  
       BusinessFacade" url="tcp://localhost:8039/SHR/SomeSystem.rem"/>
    </client>
    <channels>
      <channel ref="tcp client">
        <clientProviders>
          <formatter ref="binary" includeVersions="false"/>
          <provider 
           type="RemotingExample.Security.ClientChannelSinkProvider, 
           SecurityClient"/>
        </clientProviders>
      </channel>
    </channels>
  </application>
</system.runtime.remoting>

Не сервере приложения в ConsoleServer.exe.config:


<system.runtime.remoting>
  <application name="SHR">
    <service>
      <wellknown mode="Singleton"     
       type="RemotingExample.BusinessFacade.SomeSystem,
       BusinessFacade" objectUri="SomeSystem.rem" />
    </service>
    <channels>
      <channel name="ServerCnannel" ref="tcp server" port="8039" >
        <serverProviders>    
          <formatter ref="binary" includeVersions="false"/>
          <provider 
           type="RemotingExample.Security.ServerChannelSinkProvider, 
           SecurityServer"/>
        </serverProviders>    
      </channel>
    </channels>
  </application>
</system.runtime.remoting>

Инициализация конфигурации Remoting на Web-сервере происходит в методе:


protected void Application_Start(Object sender, EventArgs e)
{
  string configPath = System.IO.Path.Combine(Context.Server.
    MapPath(Context.Request.ApplicationPath ),"Web.config");
  RemotingConfiguration.Configure(configPath);
}

Инициализация на сервере приложения:


RemotingConfiguration.Configure("ConsoleServer.exe.config");
Диаграмма классов

На рисунке 5 приведена диаграмма используемых классов, в таблице 1 - краткое описание классов.

Рисунок 5.

Таблица 1.

Класс Сборка Описание
ServerSecurityContext SecurityServer Содержит пользовательские данные на стороне сервера приложения.
ServerChannelSinkProvider SecurityServer Провайдер канального приемника. Помещает канальный приемник в цепочку серверных канальных приемников.
ServerChannelSink SecurityServer Серверный канальный приемник. Аутентифицирует пользователей. Управляет состоянием сессии.
SecurityContextContainer SecurityBase Контейнер для пользовательских сессий.
ClientSecurityContext SecurityClient Содержит пользовательские данные на стороне Web-сервера.
ClientChannelSinkProvider SecurityClient Провайдер канального приемника на стороне Web- сервера.
ClientChannelSink SecurityClient Канальный приемник на стороне Web- сервера.
ChannelSinkHeaders SecurityBase Содержит названия заголовков аутентификации.
ISecurityContext SecurityBase Интерфейс для объектов, содержащих состояние сессии.

Аутентификация

На рисунке 6 изображен сценарий первичной аутентификации пользователя в ИС.

Рисунок 6.

Пользователь вводит логин и пароль в Web-форме. Обработчик отправки формы пытается выполнить аутентификацию:


// Создаем контекст для аутентификации.
// Цель: привязать к текущему потоку выполнения 
// аутентификационные данные,
// чтобы иметь к ним доступ из клиентского канального приемника 

ClientSecurityContext context = new 
                 ClientSecurityContext(tbName.Text,tbPassword.Text);
try 
{
  // Обращаемся к серверу приложения
  userData = (new RemotingExample.BusinessFacade.SomeSystem()).
  GetUserData();
}
catch (System.Security.SecurityException ex)
{
  //Аутентификация на сервере приложения прошла неудачно
  this.lblMessage.Text = ex.Message;
  return;
}
//Аутентификация удалась
//Создаем и записываем пользователю в Cookie билет аутентификации. 
SetAuthTiket(tbName.Text, context.SessionID);

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

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

После вызова удаленного метода:


userData = (new RemotingExample.BusinessFacade.SomeSystem()).GetUserData();

управление получает клиентский канальный применик ClientChannelSink, а именно его метод :


public void ProcessMessage(IMessage msg, 
  ITransportHeaders requestHeaders, Stream requestStream,
  out ITransportHeaders responseHeaders, out Stream responseStream)
    
//Вытаскиваем контекст запроса
ClientSecurityContext context = ClientSecurityContext.Current;

//Проверяем, аутентифицирован ли контекст  
switch (context.AuthState)
{
  case AuthenticationStates.Authenticated:
    //Если аутентифицирован, то добавляем в заголовки запроса  
    //к серверу приложения SID контекста  
    requestHeaders[ChannelSinkHeaders.SID_HEADER] = 
                                        context.SessionID;
  break;
  default :
//Иначе добавляем логин и пароль
    requestHeaders[ChannelSinkHeaders.USER_NAME_HEADER] = 
                                                context.Login;
    requestHeaders[ChannelSinkHeaders.PASSWORD_HEADER] =  
                                                сontext.Password;
  break;
}        
  
//Выполняем запрос на сервер приложения
_nextSink.ProcessMessage(msg, requestHeaders, requestStream, out     
                         responseHeaders, out responseStream);

AuthenticationStates serverAuth = 
                   AuthenticationStates.NotAuthenticated;
//Получаем заголовок состояния аутентификации сервера приложения
string serverAuthHeader =     
       (string)responseHeaders[ChannelSinkHeaders.AUTH_STATE_HEADER];
//Анализируем  полученный заголовок
switch (serverAuth)
{
//Контекст аутентифицирован на сервере приложения
case AuthenticationStates.Authenticated:
  if (context.AuthState != AuthenticationStates.Authenticated)
  {
    //На Web-сервере контекст еще не аутентифицирован
    //Создаем Principal объект для контекста
    string roles = 
         responseHeaders[ChannelSinkHeaders.ROLES_HEADER].ToString();
    string[] rolesArr = roles.Split(new char[]{','});
    IIdentity identity=new 
    GenericIdentity(ClientSecurityContext.Current.Login);
    IPrincipal userPrincipal = new GenericPrincipal(identity,rolesArr);
    //Аутентифицируем контекст
    context.SetAuthState(AuthenticationStates.Authenticated);
    context.SetPrincipal(userPrincipal);
    //Устанавливаем идентификатор сессии
    context.SetSessionID(responseHeaders[ChannelSinkHeaders.SID_HEADER].
            ToString());
//Создаем сессию на Web-сервере          
    SecurityContextContainer.GetInstance()[context.SessionID] = context;
  }  
  break;
}

Во время выполнения запроса


_nextSink.ProcessMessage(msg, requestHeaders, requestStream, 
                   out responseHeaders, out responseStream);

управление передается на сервер приложения, где в работу первым делом включается серверный канальный приемник ServerChannelSink, а именно, его метод


ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack,   
       IMessage requestMsg, ITransportHeaders requestHeaders, 
       Stream requestStream, out IMessage responseMsg, 
       out ITransportHeaders responseHeaders,  
       out Stream responseStream)

  //Получаем идентификатор сессии из заголовков запроса
  string SID = (string)requestHeaders[ChannelSinkHeaders.SID_HEADER];
  ServerSecurityContext context = null;
  if (SID == null)
  //Если SID отсутствует, пробуем аутентифицировать запрос
  {
    //Пробуем получить логин и пароль из заголовков запроса
    string userName = 
      (string)requestHeaders[ChannelSinkHeaders.USER_NAME_HEADER];
    string password =   
      (string)requestHeaders[ChannelSinkHeaders.PASSWORD_HEADER];
    AuthenticationStates authResult = 
                               AuthenticationStates.NotAuthenticated;
    if ((userName != null) && (password != null))
    {
      //Если логин и пароль найдены, выполняем аутентификацию
      string roles;
      authResult = Authenticate(userName,password, out roles);
      switch (authResult)
      {
        case AuthenticationStates.Authenticated:
          //Аутентификация прошла успешно
          //Создаем серверный контекст для пользователя
          context = new ServerSecurityContext(userName,roles);
          context.SetAuthState(AuthenticationStates.Authenticated);
          //Создаем сессию на сервере приложения
          SecurityContextContainer.GetInstance()[context.SessionID]=
                                                              context;
        break;
        default:
          //Аутентификация не удалась.   
          throw new System.Security.SecurityException("Authentication 
                        failed");
       }
     }
   }
   //Если SID существует в заголовках запроса, то авторизируем запрос 
   //по этому SID
   else
   {
     //Воостанавливаем сессию по ее идентификатору
     context = 
      (ServerSecurityContext)SecurityContextContainer.GetInstance()[SID];
     if (context == null)
     {
     throw new System.Security.SecurityException("Authorization failed");        
     }
     else
     {
       //Ассоциируем текущий контекст с полученным по SID
   ServerSecurityContext.Current = context;
     }
  }
      
  System.Security.Principal.IPrincipal orginalPrincipal = 
                  Thread.CurrentPrincipal;
  if (ServerSecurityContext.Current != null)
  {
    //Ассоциируем Principal текущего потока с 
    //Principal объектом контекста
    Thread.CurrentPrincipal = ServerSecurityContext.Current.Principal;
  }

  sinkStack.Push(this, null);
  ServerProcessing processing;
  //Выполняем полученный запрос на сервере приложения
  processing = _nextSink.ProcessMessage(sinkStack, requestMsg,  
                requestHeaders, requestStream, out responseMsg, 
                out responseHeaders, out responseStream);
  sinkStack.Pop(this);      
      
  //Восстанавливаем Principal объект для потока
  Thread.CurrentPrincipal = orginalPrincipal;
  AuthenticationStates serverAuthState =     
              AuthenticationStates.NotAuthenticated;
  if (ServerSecurityContext.Current != null) 
          serverAuthState = context.AuthState;
  responseHeaders = new TransportHeaders();
  switch (serverAuthState)
  {
    case AuthenticationStates.Authenticated:
      //Если аутентификация прошла успешно, 
      //выставляем заголовки для отправки на Web-сервер
      responseHeaders[ChannelSinkHeaders.AUTH_STATE_HEADER] =   
                              AuthenticationStates.Authenticated;
      responseHeaders[ChannelSinkHeaders.SID_HEADER] =  
                          ServerSecurityContext.Current.SessionID;
      responseHeaders[ChannelSinkHeaders.ROLES_HEADER] = 
                          ServerSecurityContext.Current.Roles;
    break;
    default :
      responseHeaders[ChannelSinkHeaders.AUTH_STATE_HEADER]=
                                                   serverAuthState;
    break;
  }
  //Очищаем текущий контекст
  ServerSecurityContext.Current = null;
  //Возвращаем управление и результаты запроса в 
  //клиентский канальный приемник
 return ServerProcessing.Complete;

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

Сценарий процесса приведен на рисунке 7.

Рисунок 7.

Первым делом в запросе пользователя к Web-серверу ищется специализированное cookie - билет аутентификации (authTicket). Этот билет содержит некоторую информацию о пользователе и говорит Web-серверу о том, что пользователь уже аутентифицирован. Для активизации этой функциональности на Web-сервере необходимо включить Forms Authentication.

Идентификация пользователя происходит в методе AuthenticateRequest Web-сервера. Этот метод вызывается сервером в начале обработки каждого запроса.


//Получаем  из Cookies билет аутентификации
string cookieName = FormsAuthentication.FormsCookieName;
HttpCookie authCookie = Context.Request.Cookies[cookieName];
System.Web.Security.FormsAuthenticationTicket authTicket = null;
try
{
  authTicket =   
      System.Web.Security.FormsAuthentication.Decrypt(authCookie.Value);
}
catch(Exception)
{
return;
}
if (null == authTicket)
{
return; 
} 
//Получаем идентификатор сессии пользователя из билета аутентификации
string sessionID = authTicket.UserData;
ClientSecurityContext securityContext = null;
//Восстанавливаем сессию пользователя по ее идентификатору
securityContext = 
 (ClientSecurityContext)SecurityContextContainer.GetInstance()[sessionID];
if (securityContext != null)
{
  ClientSecurityContext.Current = securityContext;
  //Ассоциируем Principal объект с текущим потоком 
  Context.User = securityContext.User;
}
else
{
  System.Web.Security.FormsAuthentication.SignOut();
  Response.Redirect("logout.aspx");
}

Теперь пользователь аутентифицирован на стороне Web-сервера и может выполнять программы, реализующие логику Web-приложения. В процессе выполнения этих программ Web-сервер может обращаться к серверу приложения. Естественно, что и там запрос пользователя необходимо аутентифицировать. Для этого на сервер приложения передается SID, который извлечен из билета аутентификации Web-сервером. По SID происходит аутентификация и восстанавливается пользовательская сессия на сервере приложения.

Авторизация

Функциональность авторизации реализуется с помощью атрибута System.Security.Permissions.PrincipalPermissionAttribute, устанавливаемого перед соответствующими методами фасадного объекта (BusinessFacade):


[PrincipalPermissionAttribute(SecurityAction.Demand, Authenticated=true, 
  Role = "Admin")]
public  void DoAdminWork (string arg)
{
 Console.WriteLine(DateTime.Now.ToString()+": Doing Admin work: "+arg);
}
Поддержка сессий

Осуществляется с помощью объектов ServerSecurityContext, SecurityContextContainer, ClientSecurityContext на клиентской и серверной сторонах. Инициализация сессии происходит в методах AuthenticateRequest для Web-сервера и в ProcessMessage канального приемника для сервера приложения. Объекты ISecurityContext(ServerSecurityContext, ClientSecurityContext), содержащие состояние сессии, хранятся в коллекции SecurityContextContainer. Ключом к сессии является SID (идентификатор сессии). При инициализации сессия извлекается из коллекции(SecurityContextContainer) и с помощью статического метода Current ассоциируется с текущим потоком выполнения.


public static ClientSecurityContext Current
{
  get 
  {
    ClientSecurityContext currentContext = (ClientSecurityContext)System.
      Runtime.Remoting.Messaging.CallContext.
      GetData("ClientSecurityContext");
    if (currentContext != null)
    {
      currentContext.lastActivity = DateTime.Now;
    }
    return currentContext;
  }
  set
  {
    if (value != null)
    {
      value.lastActivity = DateTime.Now;
    }
    System.Runtime.Remoting.Messaging.
          CallContext.SetData("ClientSecurityContext", value);
  }
}

После инициализации сессии ее состояние доступно в любом месте кода.


[PrincipalPermissionAttribute(SecurityAction.Demand, Authenticated=true)]
public  string  GetUserData()
{
  Console.WriteLine("GetUserData " +  
      Security.ServerSecurityContext.Current.Login);
}

Главное - проставить для этого ссылки на SecurityBase и SecurityServer(SecurityClient).

Заключение

Тестовое приложение WebCl (рисунок 8) демонстрирует возможности описанного решения. Это приложение, впрочем, как и все решение, прилагается к этой статье в виде проекта в формате Visual Studio .Net 2003.

Приведенный пример может быть расширен. Например, результатом аутентификации, помимо сообщения о ее успешности или неуспешности, может стать требование сменить пароль.

Можно организовать проверку - "один пользователь - одна сессия". Можно добавить шифрование трафика. Свойство Items объектов IsecurityContext может служить контейнером для сохранения различных объектов в сессии пользователя. Путем небольшой переработки клиентской части, это решение можно адаптировать для Windows Forms-приложений. В общем, поле для деятельности большое.

Так же можно добавить возможности для масштабирования, вынеся контейнер сессий во внешний сервис, по аналогии с ASP.NET State Service и сделав объекты сессий сериализуемыми.

Если у кого возникнут вопросы, или идеи и замечания по улучшению описанного механизма, пишите sun_shef@msn.com .

Размещение рекламы — тел. +7 495 4119920, ICQ 232284597

Подписка на новости IT-портала CITForum.ru
(библиотека, CITKIT.ru, CitCity)

Новые публикации:

24 декабря

CITKIT.ru:

  • Новогодние поздравления
  • Сергей Кузнецов. Цикл Операционные системы: Ностальгия по будущему:

  • Алексей Федорчук. OpenSolaris 2008.11 Release

  • Сергей Голубев:

  • Евгений Чайкин aka StraNNik (Блогометки):

    17 декабря

  • С.Д.Кузнецов. Базы данных. Вводный курс

    10 декабря

    CITKIT.ru:

  • OpenSolaris 2008.11 Release

  • Альтернативные ОС: две грустные истории (С.Кузнецов)
  • Nokia N810 — доведение до ума
  • CitCity:

  • Платформа 2009: заоблачные перспективы Microsoft

    4 декабря

  • Лекция С.Д.Кузнецова Понятие модели данных. Обзор разновидностей моделей данных

    CITKIT.ru:

  • OpenSolaris 2008.11 Release. Первые впечатления

  • Linux vs FreeBSD: продолжим "Священные войны"?

  • Nokia N810 as is

  • Индульгенция для FOSS

  • Друзья СПО'2008

    26 ноября

  • Нечеткое сравнение коллекций: семантический и алгоритмический аспекты

    CitCity:

    CITKIT.ru:

  • Глава из книги А.Федорчука
    Сага о FreeBSD:
  • 19 ноября

  • Проблемы экономики производства крупных программных продуктов

  • Язык модификации данных формата XML функциональными методами

    CITKIT.ru:

  • Главы из книги А.Федорчука
    Сага о FreeBSD:

    Заметки к книге:

  • FreeBSD: монтирование сменных устройств и механизм HAL
  • Текстовый редактор ee

    12 ноября

  • Правило пяти минут двадцать лет спустя, и как флэш-память изменяет правила (Гоц Грейф, перевод: Сергей Кузнецов)

    CITKIT.ru:

  • Главы из книги А.Федорчука
    Сага о FreeBSD:
  • OSS в России: взгляд правоведа (В.Житомирский)

  • Новая статья из цикла С.Голубева "Железный марш":

    29 октября

  • О некоторых задачах обратной инженерии

  • Веб-сервисы и Ruby

  • Тестирование web-приложений с помощью Ruby

    CITKIT.ru:

  • Главы из книги А.Федорчука
    Сага о FreeBSD:

  • PuppyRus Linux - беседа с разработчиком (С.Голубев)

  • Сергей Кузнецов. Заметка не про Linux

    22 октября

  • Обзор методов описания встраиваемой аппаратуры и построения инструментария кросс-разработки

    CITKIT.ru:

  • Сергей Кузнецов. Почему я равнодушен к Linux

  • Глава из книги А.Федорчука
    Сага о FreeBSD:
  • Что надо иметь
    3. Базовые познания

    CitCity:

  • Управление IT-инфраструктурой на основе продуктов Microsoft

    15 октября

  • Методы бикластеризации для анализа интернет-данных

    CitCity:

  • Разъемы на ноутбуках: что они дают и зачем их так много?
  • AMD Puma и Intel Centrino 2: кто лучше?

    CITKIT.ru:

  • Новый цикл статей С.Голубева
    Железный марш:

  • Главы из книги А.Федорчука
    Сага о FreeBSD:

    8 октября

  • Автоматизация тестирования web-приложений, основанных на скриптовых языках
  • Опыт применения технологии Azov для тестирования библиотеки Qt3

    Обзоры журнала Computer:

  • SOA с гарантией качества
  • Пикоджоуль ватт бережет
  • ICT и всемирное развитие

    CitCity:

  • Пиррова победа корпорации Microsoft

    CITKIT.ru:

  • Главы из книги А.Федорчука
    Сага о FreeBSD:

    Статья из архива:

  • Я живу в FreeBSD (Вадим Колонцов)

    Новые Блогометки:

  • Перекройка шаблона Blogger или N шагов к настоящему
  • Blogger. Comment style
  • Screenie или глянцевый снимок экрана

    2 октября

    CITKIT.ru:

  • Сага о FreeBSD (А. Федорчук)

    Zenwalk: пакет недели

  • Банинг — интеллектуальное развлечение (С.Голубев)

    CitCity:

    25 сентября

  • Клермонтский отчет об исследованиях в области баз данных

    CITKIT.ru:

  • Пользователям просьба не беспокоиться... (В.Попов)

  • Снова про ZFS: диск хорошо, а два лучше
  • Командная оболочка tcsh (А.Федорчук)

    Zenwalk: пакет недели

    17 сентября

  • T2C: технология автоматизированной разработки тестов базовой функциональности программных интерфейсов
  • Технология Azov автоматизации массового создания тестов работоспособности

    CITKIT.ru:

  • FreeBSD: ZFS vs UFS, и обе-две — против всех (А.Федорчук)

    Zenwalk: пакет недели

  • Дачнет — практика без теории (С.Голубев)

    10 сентября

  • За чем следить и чем управлять при работе приложений с Oracle
  • Планировщик заданий в Oracle
    (В.Пржиялковский)

    CITKIT.ru:

  • Microsoft: ответный "боян" (С.Голубев)

  • Причуды симбиоза, или снова "сделай сам" (В.Попов)

  • Файловые системы современного Linux'а: последнее тестирование
  • Zsh. Введение и обзор возможностей
    (А.Федорчук)

    Описания пакетов Zenwalk: Zsh, Thunar, Thunar-bulk-rename, Xfce4-places-plugin, Xfce4-fsguard-plugin

    Блогометки:

  • Google Chrome
  • Лончер для ASUS Eee PC 701

    3 сентября

    CITKIT.ru:

  • Заметки о ядре (А.Федорчук):

    Добавлены описания пакетов Zenwalk: Galculator, Screenshot, Gnumeric, Pidgin

    В дискуссинном клубе:

  • И еще о Википедии и Google Knol

  • Лекция для начинающего линуксоида (С.Голубев)

    26 августа

  • Транзакционная память (Пересказ: С. Кузнецов)

    CITKIT.ru:

  • Открыт новый проект Zenwalk: пакет недели

  • Статья Текстовые процессоры и их быстродействие: конец еще одной легенды?

    21 августа

    CITKIT.ru:

  • Почему школам следует использовать только свободные программы (Ричард Столлман)
  • Беседа Сергея Голубева с учителем В.В.Михайловым

  • Википедия или Гуглезнание? Приглашение к обсуждению (Алексей Федорчук)
  • Народная энциклопедия от Google (StraNNik)

  • Обзор Mandriva 2009.0 Beta 1 Thornicrofti
  • Новичок в Линукс: Оптимизируем Mandriva 2008.1

  • Книга Zenwalk. Приобщение к Linux:

    13 августа

    CitCity:

  • Мирный Atom на службе человеку. Обзор платы Intel D945GCLF с интегрированным процессором
  • Обзор процессоров Intel Atom 230 на ядре Diamondville

  • iPhone - год спустя. Скоро и в России?

    CITKIT.ru:

  • Интермедия 3.4. GRUB: установка и настройка (из книги Zenwalk. Приобщение к Linux)

    6 августа

  • СУБД с хранением данных по столбцами и по строкам: насколько они отличаются в действительности? (Пересказ: С. Кузнецов)

    CITKIT.ru:

  • Интермедия 2.2. Что неплохо знать для начала (из книги Zenwalk. Приобщение к Linux)

  • И снова про шрифты в Иксах (А.Федорчук)

  • 20 самых быстрых и простых оконных менеджеров для Linux

  • Дело о трех миллиардах (С.Голубев)

    30 июля

  • OLTP в Зазеркалье (Пересказ: С. Кузнецов)

    CitCity:

  • Будущее BI в облаках?
  • Тиражные приложения и заказная разработка. Преимущества для заказчика
  • Дискуссия со сторонниками заказной разработки

    CITKIT.ru:

  • Новые главы книги Zenwalk. Приобщение к Linux:
  • Глава 8. Пакеты: средства установки, системы управления, системы построения
  • Глава 9. Zenwalk: репозитории, пакеты, методы установки

    23 июля

    CITKIT.ru:

  • Все против всех. 64 vs 32, Intel vs AMD, tmpfs vs ext3
  • Две головы от Intel

  • Zenwalk: обзор штатных приложений (глава из книги "Zenwalk. Приобщение к Linux")

  • Нормально, Григорий...

    16 июля

    Обзоры журнала Computer:

  • Перспективы и проблемы программной инженерии в XXI веке
  • Большие хлопоты с большими объемами данных
  • Перспективы наноэлектроники

    CITKIT.ru:

  • Интермедия о лицензиях (А.Федорчук. "Zenwalk. Приобщение к Linux")

  • Есть ли будущее у KDE?

  • Linux в школе: альтернативный вариант в задачах

  • Шифр (приключения агента Никодима)

    10 июля

    CITKIT.ru:

  • Новые разделы книги А. Федорчука Zenwalk. Приобщение к Linux:
  • Интермедия вступительная. Linux или GNU/Linux? Как вас теперь называть?
  • Глава 5. Среда Xfce
  • Глава 6. Xfce: приложения и плагины

  • ZUR (Zenwalk User Repository) FAQ

    2 июля

  • Персистентность данных в объектно-ориентированных приложениях (С. Кузнецов)

    CITKIT.ru:

  • Новые разделы книги А. Федорчука Zenwalk. Приобщение к Linux:
  • Интермедия 1.2. Дорога к Zenwalk'у. Период бури и натиска
  • Интермедия 3.3. Немного о Linux'е и "железе"
  • Глава 4. Настройка: инструментами и руками
  • Интермедия 4.1. Zenpanel и конфиги: поиски корреляции

  • Интервью с Жан-Филиппом Гийоменом, создателем дистрибутива Zenwalk

  • Linux в школе: первые итоги (С. Голубев)

    25 июня

    CITKIT.ru:

  • Zenwalk. Приобщение к Linux (А. Федорчук)

  • Логика и риторика (С.Голубев)

  • Технология Tru64 AdvFS

  • Ханс Райзер предлагает отвести полицейских к телу Нины

    18 июня

  • Проекты по управлению данными в Google (Пересказ: С. Кузнецов)

    CITKIT.ru:

  • ОС и поддержка "железа": мифы и реальность (А. Федорчук)

  • Linux в школе: другие дистрибутивы

  • Пинок (С. Голубев)

    4 июня

  • Ландшафт области управления данными: аналитический обзор (С. Кузнецов)

    CITKIT.ru:

  • Linux в школе: слово заинтересованным лицам

  • SlackBuild: пакеты своими руками

  • Linux от компании Novell. Установка и обзор openSUSE Linux

    Все публикации >>>




  • IT-консалтинг Software Engineering Программирование СУБД Безопасность Internet Сети Операционные системы Hardware

    Информация для рекламодателей PR-акции, размещение рекламы — тел. +7 495 4119920, ICQ 232284597 Пресс-релизы — pr@citcity.ru
    Послать комментарий
    Информация для авторов
    Rambler's Top100 TopList liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня This Web server launched on February 24, 1997
    Copyright © 1997-2000 CIT, © 2001-2007 CIT Forum
    Внимание! Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав. Подробнее...