2016-01-29 4 views
1

Я знаю, что этот вопрос задавался много раньше, и он применим много разных способов и основывается на вопросах, которые я уже задал в Интернете, и здесь у меня больше вопросов чем у меня есть ответы.Spring Security 4 curl csrf token не найден

Итак, у меня есть веб-сервис 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? Когда я войти в свой веб-сайт в первый раз, у меня есть печенье, как:

JSESSIONID=openam~A7FF59011F982FBB91C2F908E143327D; path=/sso/; domain=spring-auth.mydomain.net; Secure; HttpOnly 

Теперь, когда дело доходит до заголовка: это X-CSFR-токен или X-CSFRToken ... Я видел и то, и другое.

У меня есть SimpleCORSFilter, но этот заголовок не является одним из разрешенных, нужно ли это быть? Я могу добавить его в список приемлемых заголовков.

Меня беспокоит включение _csfr в ​​данные JSON. Если я добавил его с помощью утилиты Jackson, я боюсь, что веб-сервис не будет работать, потому что у _csrf нет соответствующего объекта, поэтому я бы просто предположил, что он будет оттуда, если я это сделаю.

Итак, я сделал много проб и ошибок от завитки, и сегодня мне не очень повезло. Когда я получаю завиток, я должен передать это подрядчику, работающему над пользовательским интерфейсом. Они используют JavaScript для создания AJX-звонков в фоновый сервер, и поэтому они могут передавать все, что им нужно, в URL-адрес, отправлять данные назад, и они могут добавлять любые заголовки или куки-файлы, необходимые для передачи данных. Я оставляю это для них, чтобы понять.

Любая помощь в получении моего завитка для работы будет замечательной. Благодаря!

UPDATE: Когда пользователь входит в мое приложение, мы используем производную от примера SiteMinder. То есть мы получаем cookie из OpenAM, когда мы успешно аутентифицируем. Затем мы используем пример siteminder для вызова CustomUserDetailsService, который использует этот файл cookie для вызова OpenAM и получения имени пользователя. Затем мы выполняем поиск базы данных по этому имени пользователя, чтобы получить роли для этого пользователя. Ни в одном из них мы не получаем какой-либо токен csrf. Итак, для всех примеров, которые я видел в StackOverflow, для меня нет NO csrf token. С этим я добавил следующий веб-сервис 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 и локон ...

в 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? Как объединить их в локоть? Я знаю, что на сеанс есть один токен csrf, я хочу знать, что могу сделать один звонок и получить этот токен, а затем использовать его в следующем запросе, чтобы передать обратно POST.

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

Еще раз спасибо!

ответ

1

После долгих проб и ошибок я наконец узнал, как я могу сделать эту работу.

У меня была правильная идея, основанная на предыдущей публикации, чтобы мой собственный контроллер вернул токен, и это выделено выше. Когда я позвонил в эту службу, чтобы получить токен, я также убедился, что я схватил cookie для JSESSION. ЧТО это сеанс, который просил для запроса, так что я должен был убедиться, что я схватил, что как только я получил маркер обратно:

Cookie: JSESSIONID=3A74721AD18E758D7B8DC54FB32A6515; Path=/services/; HttpOnly 
csrf_token: db7e3100-bd2d-4ecf-8c0d-20b8b4e17b20 

Теперь, либо с Firefox RESTClient или с завитком, вам нужно две вещи :

curl \ 
-d '{"SiteId\:"548","SubjectId":TEST_sub","description":"TEST_des"}' \ 
--cookie '\JSESSIONID=3A74721AD18E758D7B8DC54FB32A6515;' \ 
--cookie "iPlanetDirectoryPro=AQIC5wM2LY4Sfcy_7ZIwOhUsE4KK922nQEue1Bgm7wAtX_k.*AAJTSQACMDE.*; path=/; domain=.mydomain.net" \ 
-H "X-CSFR-TOKEN: db7e3100-bd2d-4ecf-8c0d-20b8b4e17b20" 
-H "Accept: */*" -H "Content-Type: application/json" \ 
-H "openam-token: AQIC5wM2LY4Sfcy_7ZIwOhUsE4KK922nQEue1Bgm7wAtX_k.*AAJTSQACMDE.*" \ 
https://spring.mydomain.net/api/subject/build 

Обратите внимание, что куки для JSESSION идентификатор из запроса, я сделал, что получил токен CSRF (db7e3100-bd2d-4ecf-8c0d-20b8b4e17b20) в первую очередь. Обратите внимание, что мне нужен X-CSFR-TOKEN, чтобы включить токен, и я включил этот заголовок в SimpleCORSFilter.

Итак, это сработало !!!!! Я смог правильно передать маркер в URL-адрес, и я вижу, что он записывается в журнал. Я могу видеть доступ к контроллеру, и данные, которые я прошел в

Контроллер REST определяется как:.

@RequestMapping(value = "/build", method = RequestMethod.POST, produces = "application/json", headers = "Content-Type=application/json") 
public MyEntity build(@RequestBody SubjectImportDTO subjectImportDTO) 
{ 
    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 
    User user = null; 
    if (principal instanceof User) 
    { 
     user = ((User) principal); 
    } 
    MyEntity entity = service.build(subjectImportDTO); 
    return entity; 
} 

Теперь URL найден, вызывается, делает работу на внутреннем интерфейсе , и готова вернуть объект ...НО я получаю ошибку 404 из curl или Firefox RESTClient. Я думал, что ошибка 404 была создана, если мы даже не смогли найти конечную точку REST, так что это еще один вопрос, который у меня есть.

+0

Ошибка 404 после вызова была вызвана тем, что в этом методе метода «build» не было «@ResponseBody», потому что я использовал «@Controller» в этом классе. public MyEntity build («@ RequestBody» SubjectImportDTO subjectImportDTO) должно быть: public «@ResponseBody» MyEntity build («@ RequestBody» SubjectImportDTO subjectImportDTO) ... и это решило эту проблему. – tjholmes66

+0

Typo in curl command: X-CSFR-TOKEN - это cs * RF *, поэтому X-CSRF-TOKEN ... в случае, если кто-то другой скопирует его и задается вопросом, почему он не работает. :) – rudi

0

Я не думаю, что это в полной мере отвечает на ваш вопрос, но вот то, что я сделал, чтобы добавить маркер CSRF:

$(function() { 
    var token = $("meta[name='_csrf']").attr("content"); 
    var header = $("meta[name='_csrf_header']").attr("content"); 
    $(document).ajaxSend(function(e, xhr, options) { 
     xhr.setRequestHeader(header, token); 
    }); 
}); 

я смотрел на одном из моих заголовков запроса и его «X-CSRF-токен»

Что касается curl, я нашел другие способы тестирования, как правило, отключив CSRF в отдельной тестовой конфигурации.

+0

Одна из вещей, которые я обнаружил, заключается в том, что маркер csrf сначала возвращается клиенту. Я не могу войти в мое веб-приложение вообще, по крайней мере, не обычным способом. Ни в одном из моих запросов на бэкэнд, где я выполняю HTTP GET, не существует токена csrf. Как мне сделать какой-то запрос GET вернуть обратно токен, чтобы я мог повторно использовать его в будущем POST? – tjholmes66

Смежные вопросы