Я знаю, что этот вопрос уже много раз задавали, и он применим по-разному, и, основываясь на вопросах, которые я уже задавал в Интернете и здесь, у меня больше вопросов, чем ответов.
Итак, у меня есть веб-сервис Spring MVC 4.0 RESTful, который, как я знаю, работает нормально. Я знаю, что он работает нормально, потому что он проходит мои модульные тесты. Модульный тест с дополнительной безопасностью и "csrf()" как часть тестовой безопасности заставляет его работать. Я заметил, что эта часть данных добавлена:
Parameters = {_csrf=[435f9968-f643-47e9-9d15-23a5cb361b1d]}
Веб-служба RESTful защищена Spring Security 4, а защита csrf включена по умолчанию. Все веб-сервисы с GET отлично работают, именно POST мешает мне с ошибкой 403.
Вот завиток, который я пытаюсь реализовать:
curl \
-d '{"SiteId\:"548","SubjectId":TEST_sub","description":"TEST_des"}' \
--cookie "csrftoken=?????????????" \
--cookie "JSESSIONID=openam~A7FF59011F982FBB91C2F908E143327D" \
--cookie "iPlanetDirectoryPro=AQIC5wM2LY4Sfcy_7ZIwOhUsE4KK922nQEue1Bgm7wAtX_k.*AAJTSQACMDE.*; path=/; domain=.mydomain.net" \
-H "X-CSFRToken: ??????" -H "Accept: */*" -H "Content-Type: */*" \
-H "openam-token: AQIC5wM2LY4Sfcy_7ZIwOhUsE4KK922nQEue1Bgm7wAtX_k.*AAJTSQACMDE.*" \
https://spring.mydomain.net/api/subject/build
Итак, я знаю, что параметр -d явно выполняет POST; Я знаю, что --cookie для iPlanetDirectoryPro необходим для моего приложения. Я знаю, что нужны -H для Accept, Content-Type и openam_token.
Меня смущает следующее: -cookie для токена csfr... откуда я беру эти данные? -cookie для идентификатора сеанса или JSESSIONID? Когда я впервые захожу на свой веб-сайт, у меня есть файл cookie, например:
JSESSIONID=openam~A7FF59011F982FBB91C2F908E143327D; path=/sso/; domain=spring-auth.mydomain.net; Secure; HttpOnly
Теперь, когда дело доходит до заголовка: это X-CSFR-TOKEN или X-CSFRToken... Я видел оба.
У меня есть SimpleCORSFilter, но этот заголовок не является одним из разрешенных, так ли это? Я могу добавить его в список допустимых заголовков.
Меня беспокоит помещение _csfr в данные JSON. Используя сопоставитель Джексона, если бы я его добавил, я боюсь, что веб-служба не будет работать, потому что _csrf не имеет соответствующего объекта, поэтому я просто предположил бы, что не буду его там, если бы я это сделал.
Итак, я сделал много проб и ошибок из завитка, и сегодня мне не повезло с этим. Когда я заставлю завиток работать, я должен передать его подрядчику, работающему над пользовательским интерфейсом. Они используют JavaScript для создания вызовов AJX на серверную часть, поэтому они могут передавать все, что им нужно, обратно в URL-адрес, отправлять данные обратно и добавлять любые заголовки или файлы cookie, которые им нужны для передачи данных обратно. Я оставляю это для них, чтобы понять.
Любая помощь в том, чтобы заставить мой завиток работать, была бы здоровой. Спасибо!
ОБНОВЛЕНИЕ: когда пользователь входит в мое приложение, мы используем производную от примера SiteMinder. То есть мы получаем cookie от OpenAM при успешной аутентификации. Затем мы используем пример siteminder для вызова CustomUserDetailsService, который использует этот файл cookie для вызова OpenAM и получения имени пользователя. Затем мы выполняем поиск в базе данных по этому имени пользователя, чтобы получить роли для этого пользователя. Ни в одном из этих случаев мы не получаем какой-либо токен csrf. Итак, для всех примеров, которые я видел на StackOverflow, у меня НЕТ токена csrf, который я мог бы вернуть. При этом я добавил следующий веб-сервис RESTful.
@RequestMapping(value = "/csrf-token", method = RequestMethod.GET)
public @ResponseBody String getCsrfToken(HttpServletRequest request)
{
CsrfToken token = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
return token.getToken();
}
Я могу успешно вызвать этот URL-адрес в любое время и вернуть токен обратно клиенту. Например: "45757c25-1af7-40d3-ab8b-1a9cd823efc5"
Итак, я тестирую это в двух местах: RESTClient для Firefox и curl...
в RESTClient я могу сделать запрос и получить токен csrf, затем я пытаюсь поместить его в RESTClient следующим образом:
URL: https://spring.mydomain.net/api/subject/build?_csrf=[45757c25-1af7-40d3-ab8b-1a9cd823efc5]
Headers:
openam_token: AQIC5wM2LY4SfczkVMBTIq4pyjcec7QkyN0PJbY3NdmF8WE.*AAJTSQACMDE.*
X-CSRF-TOKEN: [45757c25-1af7-40d3-ab8b-1a9cd823efc5]
Есть ли что-то еще, что мне нужно, потому что это еще не работает.
И в завитке:
curl \
-d '{"SiteId\:"548","SubjectId":TEST_sub","description":"TEST_des"}' \
--cookie "csrftoken=45757c25-1af7-40d3-ab8b-1a9cd823efc5" \
--cookie "JSESSIONID=openam~A7FF59011F982FBB91C2F908E143327D" \
--cookie "iPlanetDirectoryPro=AQIC5wM2LY4Sfcy_7ZIwOhUsE4KK922nQEue1Bgm7wAtX_k.*AAJTSQACMDE.*; path=/; domain=.mydomain.net" \
-H "X-CSFR-TOKEN: 45757c25-1af7-40d3-ab8b-1a9cd823efc5"
-H "Accept: */*" -H "Content-Type: */*" \
-H "openam-token: AQIC5wM2LY4Sfcy_7ZIwOhUsE4KK922nQEue1Bgm7wAtX_k.*AAJTSQACMDE.*" \
https://spring.mydomain.net/api/subject/build
Опять же, что мне не хватает, чтобы сделать эту работу????
Должен ли я как-то комбинировать свой вызов в RESTClient, чтобы получить этот токен, И затем на мой POST? Как мне объединить их в curl? Я знаю, что на сеанс приходится один токен csrf, я хочу знать, что могу сделать один вызов и получить этот токен, а затем использовать его в следующем же запросе для передачи обратно для POST.
Я не занимаюсь внешним интерфейсом, у нас есть другая компания, которая работает над пользовательским интерфейсом и вызовами Ajax, я хочу иметь возможность протестировать свой вызов веб-службы, прежде чем я передам его им.
Спасибо еще раз!