Попытка защитить ресурсы с помощью OAuth в Spring MVC - PullRequest
18 голосов
/ 25 марта 2011

У нас уже есть веб-службы REST, написанные на Java на Spring MVC, и я пытаюсь защитить их.

Сервер OAuth реализован на другом веб-сайте, который обрабатывает вход в систему и создание токена доступа.Поэтому мне нужно проверить правильность токена доступа перед тем, как предоставить пользователям доступ к веб-сервисам.

Однако документация для Spring Security с OAuth кажется очень плохой, и пример кода на самом деле не объясняет, чтоэто делает!Я даже не уверен, должен ли я реализовать это для этого, так как это должна быть такая простая проверка.

Как лучше всего защитить эти веб-службы?И как лучше всего начать?

Спасибо за помощь.

1 Ответ

37 голосов
/ 22 мая 2011

Важно

[Редактировать 27.12.2012. В приведенном ниже учебнике, на который я ссылаюсь, теперь выдается 404. На github есть немного обновленная версия этого учебника. Я пробил ссылки, которые кажутся плохими. А пока я оставляю это как есть для потомков, так как пропавший учебник - тот, на который ссылается спрашивающий. Насколько мне известно, информация, содержащаяся в этом документе, по-прежнему полезна , поэтому, возможно, когда-нибудь, когда у меня будет время, я перепишу ее с новым учебником.]

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

1011 *
*

Фон

Я, конечно, могу относиться к вашим проблемам с документацией. В Spring Security, пожалуй, самая крутая кривая обучения среди всех проектов Spring, и поддержка OAuth довольно новая и поддерживается отдельно от Spring Security. Документы Spring Security OAuth являются разреженными.

Если у вас нет хорошего восприятия OAuth, найдите его! Вы просите своих пользователей доверять безопасности реализации этого стандарта на вашем сайте. Таким образом, вы не можете допустить двусмысленности в понимании предмета! Очевидное место для начала - OAuth.net и Руководство для начинающих OAuth в Вселенной.

Если / как только вы почувствуете, как работает OAuth, я настоятельно рекомендую прочитать списки документации Spring Security " Getting Started " и " Articles and Tutorials " чтобы понять, как вообще реализована Spring Security.

Как только вы получите достаточные знания о Spring Security и примете OAuth, официальное руководство пользователя Spring Security OAuth начнет обретать смысл. Вы должны обратить внимание, в частности, на разделы Consumer / Client для версии OAuth, с которой вы работаете ( 1.0 или 2.0 ).

На этом же сайте также есть приличное учебное пособие для OAuth 1.0 и OAuth 2.0, основанное на втором разделе сервисов Руководство для начинающих OAuth упомянутое выше.

Доступ к защищенным ресурсам Restful

Для вашей проблемы мы сосредоточимся на реализации сервиса фотопечати Tonr из учебника , упомянутого выше. Этот сервис печатает фотографии, которые являются OAuth-защищенными ресурсами, размещенными на внешних сайтах. Tonr использует эти сайты для контроля доступа к этим ресурсам. Это будет включать в себя перенаправление пользователя для аутентификации пользователя и подтверждение аутентификации при необходимости.

Сервисы / контроллеры Spring-MVC REST, которые сами являются потребителями внешних ресурсов, защищенных OAuth, реализуют это поведение «отложенной авторизации» (мой термин) с помощью фильтров запросов. В соответствии с 1.0 руководство пользователя :

Есть два фильтра запросов, которые применимо к потребителю OAuth логика. Первый фильтр, OAuthConsumerContextFilter , есть ответственность за создание OAuth-специфический контекст безопасности, очень похож на Spring Security's SecurityContext . Контекст безопасности просто содержит набор токенов доступа которые были получены для текущий пользователь. Этот контекст безопасности используя при запросах защищенные ресурсы.

Есть еще один фильтр запросов, OAuthConsumerProcessingFilter , что может применяться к определенным URL или URL шаблоны, которые требуют доступа к удаленный защищенный ресурс. Ввод этот фильтр в Spring Security Цепочка фильтров гарантирует, что любой токены доступа, необходимые для указанного URL-паттерны будут получены раньше разрешение доступа к ресурсам.

Итак, как вы можете видеть, для OAuth 1.0 фильтрация запросов с допустимым OAuthConsumerProcessingFilter будет обрабатывать все, что связано с получением действительных токенов доступа, а также уведомлять пользователя, когда доступ запрещен.Также существуют соответствующие классы OAuth2ClientContextFilter и OAuth2ClientProcessingFilter.

Наконец, после того, как все это настроено, вы можете получить доступ к защищенным OAuth-ресурсам в своих контроллерах с помощьюOAuthRestTemplate или OAuth2RestTemplate, как если бы вы обращались к незащищенным ресурсам с помощью обычного RestTemplate (info здесь ).Однако они должны быть внедрены в ваш сервис или контроллер с экземпляром ProtectedResourceDetails или OAuth2ProtectedResourceDetails .

У меня есть хорошие новости, если это звучит сложно.Вся эта ерунда обычно абстрагируется и обрабатывается для вас пространствами имен OAuth и OAuth2 XML

Пространство имен oauth демонстрируется в XML-файлах конфигурации Tonr, расположенных в соответствующих каталогах src / webapp / WEB-INF.,Приведенные ниже примеры сокращены непосредственно оттуда.

Если вы хотите посмотреть, как на стороне поставщика работает без с использованием пространств имен OAuth, я бы предложил вам проверить на этом форуме SpringSourceотправьте и следите за выпуском SECOAUTH-53 для получения обновлений.

OAuth 1.0 Пример

Tonr использует службы, защищенные OAuth, от Sparklr и Google здесь, поэтомуон устанавливает ProtectedResourceDetailsService, называемый resourceDetails, используя тег oauth:resource-details-service.Затем он устанавливает OAuthConsumerContextFilter и OAuthConsumerProcessingFilter со ссылкой на resourceDetails с помощью тега oauth:consumer.Эти фильтры создаются с экземплярами ProtectedResourceDetails для каждого из защищенных поставщиков ресурсов с помощью тега oauth:resource.

Из приложения tonrContext.xml:

<oauth:consumer resource-details-service-ref="resourceDetails" oauth-failure-page="/oauth_error.jsp">
  <oauth:url pattern="/sparklr/**" resources="sparklrPhotos"/>
  <oauth:url pattern="/google/**" resources="google"/>
</oauth:consumer>

<oauth:resource-details-service id="resourceDetails">
  <oauth:resource id="sparklrPhotos"
                  key="tonr-consumer-key"
                  secret="SHHHHH!!!!!!!!!!"
                  request-token-url="http://localhost:8080/sparklr/oauth/request_token"
                  user-authorization-url="http://localhost:8080/sparklr/oauth/confirm_access"
                  access-token-url="http://localhost:8080/sparklr/oauth/access_token"/>
  <!--see http://code.google.com/apis/accounts/docs/OAuth_ref.html-->
  <oauth:resource id="google" key="anonymous" secret="anonymous"
                  request-token-url="https://www.google.com/accounts/OAuthGetRequestToken"
                  user-authorization-url="https://www.google.com/accounts/OAuthAuthorizeToken"
                  access-token-url="https://www.google.com/accounts/OAuthGetAccessToken"
                  request-token-method="GET"
                  access-token-method="GET">
    <oauth:addtionalParameter name="scope" value="https://picasaweb.google.com/data/"/>
    <oauth:addtionalParameter name="xoauth_displayname" value="Tonr Example Application"/>
  </oauth:resource>
</oauth:resource-details-service>

Затем создаются компоненты sparklrService и googleService, каждый со своим внутренним компонентом OAuthRestTemplate, каждый из которых получает ссылку через constructor-arg на соответствующий ProtectedResourceDetails, который был создан ранее и введен в ProtectedResourceDetailsService боб.

Из файла tonr spring-servlet.xml:

<bean id="sparklrService" class="org.springframework.security.oauth.examples.tonr.impl.SparklrServiceImpl">
  <property name="sparklrPhotoListURL" value="${sparklrPhotoListURL}"/>
  <property name="sparklrPhotoURLPattern" value="${sparklrPhotoURLPattern}"/>
  <property name="sparklrRestTemplate">
    <bean class="org.springframework.security.oauth.consumer.OAuthRestTemplate">
      <constructor-arg ref="sparklrPhotos"/>
    </bean>
  </property>

</bean>
<bean id="googleService" class="org.springframework.security.oauth.examples.tonr.impl.GoogleServiceImpl">
  <property name="googleRestTemplate">
    <bean class="org.springframework.security.oauth.consumer.OAuthRestTemplate">
      <constructor-arg ref="google"/>
    </bean>
  </property>

</bean>

OAuth 2.0 Пример

Мое понимание здесь немного слабее. Отчасти причина этого в том, что пространство имен OAuth2 выглядит намного более абстрактным.Кроме того, похоже, что пример Tonr 2 не был конкретизирован так же, как и оригинальный пример Tonr.Я приложу все усилия и при необходимости отредактирую.

Сначала создается тег oauth:client и ему дается ссылка на компонент InMemoryOAuth2ClientTokenServices.Похоже, что это устанавливает соответствующие фильтры.Затем создаются бобы OAuth2ProtectedResourceDetails для sparklr и Facebook с oauth:resource.

Из приложения tonr 2Context.xml:

<!--apply the oauth client context-->
<oauth:client token-services-ref="oauth2TokenServices"/>

<beans:bean id="oauth2TokenServices" class="org.springframework.security.oauth2.consumer.token.InMemoryOAuth2ClientTokenServices"/>

<!--define an oauth 2 resource for sparklr-->
<oauth:resource id="sparklr" type="authorization_code" clientId="tonr"
                  accessTokenUri="http://localhost:8080/sparklr/oauth/authorize"
                  userAuthorizationUri="http://localhost:8080/sparklr/oauth/user/authorize"/>

<!--define an oauth 2 resource for facebook. according to the facebook docs, the 'clientId' is the App ID, and the 'clientSecret' is the App Secret -->
<oauth:resource id="facebook" type="authorization_code" clientId="162646850439461" clientSecret="560ad91d992d60298ae6c7f717c8fc93"
                  bearerTokenMethod="query" accessTokenUri="https://graph.facebook.com/oauth/access_token"
                  userAuthorizationUri="https://www.facebook.com/dialog/oauth"/>

Далее, как и в предыдущем примере, каждый контроллер или компонент службы, которому требуется доступ к защищенному ресурсу, создается с помощью внутреннего компонента OAuth2RestTemplate.Этому внутреннему компоненту дается ссылка на правильный компонент OAuth2ProtectedResourceDetails через constructor-arg.

Из Spring-servlet.xml 2 тонры:

<bean id="facebookController" class="org.springframework.security.oauth.examples.tonr.mvc.FacebookController">
  <!-- snipped irrelevant properties -->
  <property name="facebookRestTemplate">
    <bean class="org.springframework.security.oauth2.consumer.OAuth2RestTemplate">
      <constructor-arg ref="facebook"/>
    </bean>
  </property>
  <property name="tokenServices" ref="oauth2TokenServices"/>
</bean>

<bean id="sparklrService" class="org.springframework.security.oauth.examples.tonr.impl.SparklrServiceImpl">
  <!-- snipped irrelevant properties -->
  <property name="sparklrRestTemplate">
    <bean class="org.springframework.security.oauth2.consumer.OAuth2RestTemplate">
      <constructor-arg ref="sparklr"/>
    </bean>
  </property>
  <property name="tokenServices" ref="oauth2TokenServices"/>
</bean>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...