springSecurityService.principal возвращает Null при развертывании как WAR в tomcat 8.5

Преамбула

Я разрабатываю шлюз API для федерации микросервисов Grails. Эта проблема связана с рядом проблем, уже зарегистрированных в этом репозитории но ничего не дает решения.

Версии и конфигурации

Грааль: 3.2.2

Кот: 8,5

Версии плагина:

compile 'org.grails.plugins:spring-security-core:3.1.2'
compile "org.grails.plugins:spring-security-rest:2.0.0.M2"

Я использую плагин Spring Security Rest только для аутентификации токена. Я сам выполняю часть авторизации, возвращая ROLE_NO_ROLES для всех пользователей в getAuthorities(). Я перехватываю все запросы и разрешаю доступ на основе моей собственной схемы авторизации, хранящейся в БД.

Проблема:

С этими конфигурациями и стратегией мой код работает так, как нужно, когда я запускаю его в своей локальной системе. Когда я его развертываю на сервере как war-файл в tomcat, он отлично работает для всех запросов к шлюзу, т.е. для всех запросов шаблона /umm/controller/action. Есть контекст безопасности Spring, и пользователь оценивается отлично.

Когда я пытаюсь вызвать другие микросервисы путем перенаправления с запросами вида /umm/microservice/controller/action, springSecurityService.getCurrentUser() и springSecurityService?.principal?.username, начинают возвращаться null. Хотя мой токен отлично оценивается, я не получаю никакого контекста безопасности.

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

Обновление: 19 мая 2017 г.

Я попытался развернуть свою войну в Tomcat на моей локальной машине. Этот вопрос и этот question предоставляют следующие решения.

  • отключение кеша tomcat
  • настройка grails.plugin.springsecurity.sch.strategyName = org.springframework.security.core.context.SecurityContextHolder.MODE_INHERITABLETHREADLOCAL

Кажется, пока ничего не работает. SecurityContextHolder все равно возвращает null. Все пользовательские функции извлечения SpringSecurityService, а именно. getCurrentUser(), getPrincipal(), getAuthentication() и loadCurrentUser() возвращают значение null.

Обновление: 23 мая 2017 г.

Чтобы сузить проблему, я выполнил автономную войну, используя

java -Dgrails.env=prod -jar build/libs/mywar-0.1.war

Теперь для любого запроса, отличного от umm, я получаю 404, page not found. Я думаю, что проблема связана с производственной средой. Приложение отлично работает в разработке.

Также попробовал grails run-app, который отлично работает. Чтобы исключить проблему с производственной средой, я создал войну с помощью grails dev war, но безрезультатно. На war пока ничего не работает.

Обновление: 25 мая 2017 г.

Вероятно, мне следует задать этот вопрос http://security.stackexchange.com, но для протокола я задаю его и здесь.

Ответ, предоставленный мной ниже, содержит исправление обходного пути. Механизм, с помощью которого работает исправление, объясняется в ответе. Мой вопрос:

  1. Приводит ли этот подход к какой-либо уязвимости или лазейке в системе безопасности?
  2. Безопасна ли эта схема авторизации или ее нужно пересмотреть?
  3. Я аутентифицируюсь через плагин, но авторизуюсь сам. Может ли кто-нибудь обойти фильтры безопасности и напрямую попасть в перехватчик авторизации? Потому что, если кто-то может это сделать, ему нужно будет только дать мне имя пользователя администратора в том же формате, что и токен, и он будет иметь доступ ко всему.

person Saqib Ahmed    schedule 16.05.2017    source источник


Ответы (1)


Обходной путь

У меня есть решение проблемы. Поскольку мне нужно было только имя пользователя, я захватил оставшийся токен в своем перехватчике, расшифровал его и извлек из него имя пользователя.

Вот оно:

def extractUsername(def token){
    Base64 coder = new Base64()
    def tok = token - "Bearer "
    def principal = tok.tokenize(".")
    def dec = coder.decode(principal[1])
    def sub = new String(dec)
    def user = sub.tokenize(",")
    def username=user[1].tokenize(":")
    username = username[1]-"\""
    return username-"\""
}

Это сработало для меня, потому что мне не нужно было проверять объект springSecurityService.Principal. Если бы это было так, я бы не смог получить имя пользователя. springSecurityService.Principal и springSecurityService.getCurrentUser() по-прежнему возвращают значение null. Проблема еще не решена. Я отвечаю, потому что не получил ни одного комментария, несмотря на награду. Ответ на исходный вопрос по-прежнему приветствуется, если кто-нибудь может объяснить, почему spring-security-plugin ведет себя таким образом.

Изменить: 25 мая 2017 г.

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

Это оригинальный токен, сгенерированный плагином Spring Security REST для Grails:

eyJhbGciOiJIUzI1NiJ9.eyJwcmluY2lwYWwiOiJINHNJQUFBQUFBQUFBSlZTUDBcL2JRQlJcL0RrRkJpbWdCcVpVNjBLVjBxeHlKanBsSVNwRXFLNmthc2xDcDZHSVwvM0lQem5iazdrMlNwTXBXQkFVU0xWSld2d0RlQmhROVF0VU5YNXE1OVp3aE91eUJ1c2ZYdTU5K1wvNTdNcm1EWWFYc2FhY1dIOFZHUXhsNzVKTlpleHdURFQzQTc5ektDTzBPYUl0UnpZcFFsY0g2OEVYZ0FsSGxsWUNMYlpIcXNKSnVOYXU3ZU5vYTBQTkN3ckhkOHdibW1XWUZcL3BIZitXTzFRYVwveEVvcUwzdkphaHN3RHdMUTVWSjIxSnlkWkJ5amRFR3pCV3pRSVU3YnZRb3BCdVVsak5oSnFFVmxLd25NQXFneWpMN1VaRXFSMlBoNGJYWnpISlI2NkN0QnpDVE1tUEkzWDlKT3RaWmRcL2ZPcHFRRXVcL0FKeW9QVW8wUGRQWGRRM1wvSDRUU1VFcGVaS21xV3VURlRFdDdnVEpcLzdSNHZIbDRlbW9Xd0tnVGw3Y1wvVTB4ZjlLQTBmbUhQMFwvem9yM1F3dU1KNndXc1Brakp6WHpCdks3UktmXC80OXZiTHlkWCsreWxTZG9qWDk5XC9IMHNwTmM4T21TbEttbVZVVE95TGFmdG05RTNuamJ2THhGb1oraHllcFFQcWpwTVhvVnFJZ3ByaGxyY1M0Ynd1ejc5ckI2bWFydmVtZUhUZXBzQ2poOGxXRHBCXC9reWQzS1wvRURSd2c1K0gxMGNQdnRKTkc5Z2VvK0pES240dVFMVXlwSWU2czluSjR2VnI3OE84aGpqWFwvb3Z4RG9UU3hZREFBQT0iLCJzdWIiOiJhZG1pbkRCIiwicm9sZXMiOlsiUk9MRV9OT19ST0xFUyJdLCJleHAiOjE0OTU3MTU3OTMsImlhdCI6MTQ5NTcxMjE 5M30.MPEXURGhJo5s75LfUSm5ckG99Byc7FCLyj1gYZJu1zk

Это расшифрованная версия:

"principal":"H4sIAAAAAAAAAJVSP0/bQBR/DkFBimgBqZU60KV0qxyJjplISpEqK6kaslCp6GI/3IPznbk7k2SpMpWBAUSLVJWvwDeBhQ9QtUNX5q59ZwhOuyBusfXu59+/57MrmDYaXsaacWH8VGQxl75JNZexwTDT3A79zKCO0OaItRzYpQlcH68EXgAlHllYCLbZHqsJJuNau7eNoa0PNCwrHd8wbmmWYF/pHf+WO1Qa/xEoqL3vJahswDwLQ5VJ21JydZByjdEGzBWzQIU7bvQopBuUljNhJqEVlKwnMAqgyjL7UZEqR2Ph4bXZzHJR66CtBzCTMmPI3X9JOtZZd/fOpqQEu/AJyoPUo0PdPXdQ3/H4TSUEpeZKmqWuTFTEt7gTJ/7R4vHl4emoWwKgTl7c/U0xf9KA0fmHP0/zor3QwuMJ6wWsPkjJzXzBvK7RKf/49vbLydX++ylSdojX99/H0spNc8OmSlKmmVUTOyLaftm9E3njbvLxFoZ+hyepQPqjpMXoVqIgprhlrcS4bwuz79rB6marvemeHTepsCjh8lWDpB/kyd3K/EDRwg5+H10cPvtJNG9geo+JDKn4uQLUypIe6s9nJ4vVr78O8hjjX/ ovxDoTSxYDAAA=","sub":"adminDB","roles":["ROLE_NO_ROLES"],"exp":1495715793,"iat":1495712193

Принципал здесь подписан и зашифрован, но имя пользователя не зашифровано. Таким образом, его можно легко извлечь с помощью кода, приведенного выше.

person Saqib Ahmed    schedule 23.05.2017