LINUX.ORG.RU

[очередной мой тред] Authentication


0

2

Я перестал верить что смогу как-то это замутить без контейнера, так что теперь котейнер приложений/серверов допускаю

Есть экземляр POJO, который реализует мой интерфейс. Надо получить к нему удаленный доступ с автентификацией. Требования

  • Authentication по логину и паролю
  • После успешного логина у пользователя есть роль, которая используется для method level authentication с помощью аннотаций
  • логины, пароли, роли лежат в бд
  • переносимо между контейнерами. Вот тут основная проблема. Гугол дает статьи, где надо возиться в realms, а это контейнеро-специфичная фича. Хотелось бы вообще контейнер никак не конфигурировать, приложение должно деплоится без доп.конфигов.

Предыдущие решения

  • Spring, http invoker. Описал как решил здесь. Все бы ничего, только там логин происходит в глобальный сферический контекст в вакууме. Тоесть всем юзерам открывается доступ на уровне первого залогиневшегося.
    if (SecurityContextHolder.getContext().getAuthentication() == null) {
                Authentication request = new UsernamePasswordAuthenticationToken(username, password);
                Authentication result = getAuthenticationManager().authenticate(request);
                SecurityContextHolder.getContext().setAuthentication(result);
                return true;
            } else {
                return true;
            }

    Если убрать проверку на null, то логин происходит с каждым запросом. Это работает, но это рулетка, логин все равно общий - значит идиотизм и отпадает.

  • JAX-WS. Это счастье совсем непонятно как пропустить через автентификацию на уровне приложения. Нужно конфигурячить контейнер и каждый раз по-разному. Может проблему поможет решить Spring? Пока не могу нагуглить как это делается с учетом ВСЕХ требований вверху.
  • EJB. Еще не пробовал, тяжелая артиллерия. А больше никак?
★★★★★

Все бы ничего, только там логин происходит в глобальный сферический контекст в вакууме.

Храни признак залогиненности в БД. От пользователя требуй некий uid, выдаваемый при логине и записываемый в бд. Если пользователь логиниться повторно, создаешь еще один uid и его тоже помечаешь как залогиненный. Можно вместо бд использовать memcached. Авторизуешь пользователей через фильтр или что у тебя там. Короче берешь у пользователь uid, находишь principal по нему и ставишь в thread-local переменную.

dizza ★★★★★
()
Ответ на: комментарий от dizza

Вручную я могу решить эту задачу 100500 разными способами. Дело не к спеху и хочется все кошерненько

vertexua ★★★★★
() автор топика
Ответ на: комментарий от isden

http://www.springbyexample.org/examples/simple-spring-security-webapp.html

На JAX-WS будет распространяться? По логике да, но на практике будет? Но ок, попробую, я видел эту статью.

http://www.artoria.ru/2009/04/ajax-аутентификация-с-помощью-spring-security/

Какой-то PHP-way. Думаю можно как-то по другому после почти 20 лет развития Java

vertexua ★★★★★
() автор топика
Ответ на: комментарий от vertexua

Вручную я могу решить эту задачу 100500 разными способами. Дело не к спеху и хочется все кошерненько

В жаве слишком мало «кошерненького», поэтому приходится писать сверхзвковые велосипеды. Кошерненько - это я так понимаю, что бы просто, из каропки, да еще и не перегружено всяким интепрайз шитом. Так вот такого мало.

dizza ★★★★★
()
Ответ на: комментарий от vertexua

> На JAX-WS будет распространяться? По логике да, но на практике будет? Но ок, попробую, я видел эту статью.

хз, я этим не пользовался. отпишись плз по результатам, мне это тоже интересно в перспективе :)

isden ★★★★★
()
Ответ на: комментарий от isden

Ручками. Я раньше тоже любил поспорить с «велосепедистами». Пока сам не попробовал. Без гавно-фреймворков оно и проще получается, и надежнее (если руки из нужного места растут), да и производительнее. Сейчас вот занимаюсь переводои одного крупного проекта с java security на самопальное решение.

dizza ★★★★★
()
Ответ на: комментарий от dizza

Ну в общем велосипедостроение - метария тонкая, но в части security согласен, не видел в джаве ни одного решения, которое бы мне понравилось.

Legioner ★★★★★
()
Ответ на: комментарий от Legioner

Да, точно тонкая. Высший пилотаж можно сказать. Но ТС все правильно делает - пока говнеца не хлебнешь из всяких спрингов, не осенит, что же в этом мире стоит улучшить.

dizza ★★★★★
()
Ответ на: комментарий от isden

Заработало.

Архитектура вкратце такая.

  1. Apache Tomcat 6
  2. На нем крутится JAX-WS вебсервис.
  3. Через XML заданы юзеры
       <security:authentication-manager>
           <security:authentication-provider>
            <security:password-encoder hash="md5" />
            <security:user-service>
                <security:user name="david" password="369389d19e24204b4927e30dd7c39efc" authorities="ROLE_USER,ROLE_ADMIN" />
                <security:user name="alex" password="847c6f184197dc1545d9891d42814a7d" authorities="ROLE_USER" />
                <security:user name="tim" password="0513111ff330e25c631b5d3e9c0a4aae" authorities="ROLE_USER" />
            </security:user-service>
           </security:authentication-provider>
       </security:authentication-manager>
    Это копипаст из инета. Весь этот тег в продакшне заменяется на
    <security:jdbc-user-service data-source-ref="dataSource" />
    
  4. Аннотации завел вот так
        <context:component-scan base-package="wsserver1"   />
        <context:annotation-config/>
        
        <bean id="myService" class="wsserver1.MyServiceImpl">
    
        </bean>
    
        <security:global-method-security jsr250-annotations="enabled"/>
     
        <security:http auto-config="true">
           <security:intercept-url pattern="/MyServiceEndpoint*" filter="none" />
           <security:intercept-url pattern="/**" access="ROLE_USER" />
           <security:http-basic/>
        </security:http>

    Отдельное правило для выкачивания WSDL, а потому нужен как минимум ROLE_USER. Это единственное что еще не доделал. Система не дает выкачать wsdl. Что-то там не так, говорит 401. Но это уже последние шаги, так как если не заморачиваться этими строками и удалить все intercept-url, то все работает как надо. Может так и сделать? Просто я хотел одним махом открыть анонимусу только WSDL, а сервис уже отдавать только юзеру.

  5. На клиенте
    <bean id="myService" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
        <property name="serviceInterface" value="wsserver1.MyService"/>
        <property name="wsdlDocumentUrl" value="http://localhost:8080/wsserver1/MyServiceEndpoint?wsdl"/>
        <property name="namespaceUri" value="http://wsserver1/"/>
        <property name="serviceName" value="MyService"/>
        <property name="portName" value="MyServiceEndpointPort"/>
        <property name="username" value="alex"/>
        <property name="password" value="newjersey"/>
        <property name="lookupServiceOnStartup" value="true"/>
    </bean>
    public class Main {
    
        /**
         * @param args the command line arguments
         */
        public static void main(String[] args) {
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test1/context.xml");
            MyService service = (MyService)context.getBean("myService");
            for (UserInfo u: service.getUsers())
                System.out.println(u.getName()+" "+u.getPassword());
        }
    
    }
  6. Остальное по мануалу.
    @WebService
    public interface MyService {
        @WebMethod
        public UserInfo[] getUsers();
    }
    public class MyServiceImpl implements MyService{
    
        @RolesAllowed({"ROLE_ADMIN"})
        public UserInfo[] getUsers() {
            List<UserInfo> users = new ArrayList<UserInfo>();
            users.add(new UserInfo("user","password"));
            users.add(new UserInfo("admin","a_password"));
            return users.toArray(new UserInfo[0]);
        }
        
    }
    @WebService
    public class MyServiceEndpoint extends SpringBeanAutowiringSupport implements MyService{
        @Autowired
        MyService myService;
    
        @WebMethod
        public UserInfo[] getUsers(){
            return myService.getUsers();
        }
    
    }
  7. Для меня три класса - толсто, и аннотаций много. Притензий нет только к Impl. У MyServiceEndpoint проблема - неясность его необходимости. Он нужен просто потому что не создается контекстом Spring? Потому по Autowired его связывают с тем же говном, только который создан внутри контекста? Очень грустно тогда. Каждый метод реализовывать в десяти местах.
  8. У MyService непонятно зачем туда тащить Web* аннотации. По мануалу не надо, а на практике если через этот же интерфейс работать на клиенте, то отправляет без этих аннотаций лесом. В ошибке так и говорит.
vertexua ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.