Unable to validate saml message ошибка инициализации

При возникновении ошибок, связанных с SAML (языком разметки декларации безопасности), следуйте инструкциям ниже.

Чтобы вам было проще устранять неполадки, воспользуйтесь инструментом кодирования и декодирования для обработки запросов и ответов SAML из файла в формате HTTP Archive Format (HAR) в словесной форме.

Ошибки при добавлении приложения SAML

При добавлении приложения SAML в консоль администратора может возникнуть ошибка 400.

400 неуникальный идентификатор объекта

Это сообщение появляется, когда вы пытаетесь добавить приложение с уже существующим идентификатором объекта.

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

Используйте уже настроенное приложение или укажите другой идентификатор объекта.

500 ошибки при создании приложения SAML

При добавлении SAML-приложения в консоли администратора вы можете столкнуться с ошибками 500. Они появляются в следующих случаях:

  • В разделе Сведения о поставщике идентификационной информации Google вы нажали кнопку Скачать сертификат или Скачать метаданные, когда сервер сертификатов был недоступен.
  • Во время загрузки схемы при сопоставлении идентификатора названия или атрибута, если превышено время ожидания отклика от сервиса схем или возникли ошибки на сервере.
  • Сервис настройки поставщика услуг недоступен. Ошибка 500 возникает на последнем этапе, когда вы нажимаете Готово.

Чтобы устранить ошибки 500 при добавлении SAML-приложения:

При возникновении этих проблем подождите немного и повторите попытку. Если ошибку устранить не удалось, обратитесь в службу поддержки Google Cloud.

Ошибки выполнения SAML

Если в ходе процессов, запущенных поставщиком услуг или поставщиком услуг идентификации (IdP), вы использовали систему единого входа на базе SAML, могут возникнуть следующие ошибки:

403 app_not_configured (приложение не настроено)

Эта ошибка может появиться в следующих случаях:

  • Приложение, соответствующее указанному в запросе идентификатору объекта, не было добавлено в консоль администратора.

  • Идентификатор объекта, указанный в запросе SAML, не соответствует ни одному из идентификаторов для существующих приложений. Если кто-либо исказил идентификатор приложения, указанный в URL от поставщика услуг идентификации, вы увидите ошибку app_not_configured.

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

  1. Убедитесь, что приложение, соответствующее идентификатору объекта в запросе, было установлено до отправки этого запроса.
  2. Удостоверьтесь, что идентификатор объекта в запросе SAML указан правильно и соответствует выбранному приложению.
  3. Убедитесь, что идентификатор поставщика услуг в URL запроса соответствует значению, указанному для приложения.

403 app_not_configured_for_user (приложение не настроено для пользователя)

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

Убедитесь, что значение тега saml:Issuer в запросе SAML совпадает со значением идентификатора объекта, заданным для SAML-приложения в разделе Сведения о поставщике услуг консоли администратора. Значение чувствительно к регистру.

403 app_not_enabled_for_user (приложение не включено для пользователя)

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

  1. В списке приложений найдите SAML-приложение, из-за которого возникает ошибка.
  2. Нажмите на его название, чтобы открыть страницу настроек.
  3. Выберите Доступ пользователей.
  4. Включите приложение для всех пользователей или для нужного организационного подразделения.

400 saml_invalid_user_id_mapping (неправильное сопоставление имени пользователя в SAML)

Если в запросе SAML поставщик услуг отправил параметр Идентификатор названия, он должен соответствовать значению, указанному на стороне поставщика идентификационной информации. В противном случае система выдаст ошибку.

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

  1. Откройте раздел Основные сведения и проверьте параметр Идентификатор названия.
  2. Убедитесь, что он соответствует значению запроса SAML, указанному на стороне поставщика идентификационной информации.

400 saml_invalid_sp_id (SAML неправильный идентификатор поставщика услуг)

Ошибка возникает, если идентификатор поставщика услуг в URL указан неверно, так как был некорректно настроен или подменен.

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

  1. Откройте раздел Основные сведения и проверьте идентификатор приложения.

  2. Убедитесь, что идентификатор поставщика услуг в URL запроса соответствует значению, указанному для приложения.

Иногда в ответ на запрос SAML приходит отказ. В этом случае может появиться одно из трех сообщений об ошибке, указанных ниже.

Недопустимый запрос от поставщика услуг, URL ACS в запросе не соответствует настроенному

Эта ошибка означает, что URL ACS в запросе SAML не соответствует значению, указанному для приложения в консоли администратора.

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

  1. Перейдите в раздел Сведения о поставщике услуг.

  2. Введите URL ACS, который указан в запросе SAML.

Недопустимый идентификатор поставщика услуг идентификационной информации в URL

Указанный в URL идентификатор поставщика идентификационной информации (зашифрованный идентификатор клиента) был искажен и является некорректным.

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

  1. Перейдите в раздел Безопасностьа затемНастройка системы единого входа для SAML-приложений.

  2. В конце URL идентификатора объекта найдите идентификатор поставщика услуг идентификационной информации.

  3. Убедитесь, что он соответствует идентификатору, указанному в URL запроса.

Недопустимый идентификатор поставщика услуг идентификации в запросе

URL системы единого входа со стороны поставщика услуг идентификации был искажен. Идентификатор поставщика скрытым образом изменен на идентификатор другого клиента.

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

  1. Перейдите в раздел Безопасностьа затемНастройка системы единого входа для SAML-приложений.

  2. В конце URL идентификатора объекта найдите идентификатор поставщика услуг идентификационной информации.

  3. Убедитесь, что он соответствует идентификатору, указанному в URL запроса.

Ошибки 500 при тестировании системы единого входа на базе SAML

Когда пользователи выполняют аутентификацию в системе единого входа на базе SAML через поставщика услуг или поставщика услуг идентификационной информации, они могут столкнуться с одной из ошибок 500 из-за недоступности сервера.

Чтобы устранить ошибки 500 при тестировании системы единого входа на базе SAML:

При возникновении этих ошибок подождите немного и повторите попытку. Если неполадку устранить не удалось, обратитесь в службу поддержки Google Cloud.

Сообщения об ошибках доступа к приложениям SAML

1000 ошибка доступа к приложению SAML

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

Обратитесь в службу поддержки Google Cloud.

1000 ошибка доступа к настройкам приложения SAML

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

Обратитесь в службу поддержки Google Cloud.

Сообщение об ошибке в приложении SAML при удалении схемы пользователя

400

Эта ошибка возникает, если вы пытаетесь удалить специальную схему, которая выполняет роль сопоставления атрибутов для удаленного SAML-приложения. Ошибка 400 может возникать, если вы создали схему до устранения этой проблемы.

Чтобы исправить ошибку, выполните следующие действия:

Обратитесь в службу поддержки Google Cloud.

Эта информация оказалась полезной?

Как можно улучшить эту статью?

Обновлено: 28.01.2023

Не открывается, не грузится, не доступен, лежит или глючит?

Что не работает?

Кэш браузера.
Чтобы удалить кэш и получить актуальную версию страницы, обновите в браузере страницу с помощью комбинации клавиш Ctrl + F5.

Блокировка доступа к сайту.
Очистите файлы cookie браузера и смените IP-адрес компьютера.

DNS-кэш.
Очистите DNS-кэш на вашем компьютере и повторите попытку доступа на сайт. Смотреть видео-инструкцию ↓

VPN и альтернативные службы DNS.
VPN: например, мы рекомендуем NordVPN.
Альтернативные DNS: OpenDNS или Google Public DNS.

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

Сбой драйвера микрофона
Быстро проверить микрофон: Тест Микрофона.

или рассказать о сегодняшнем сбое без регистрации
идентификация не требуется
комментарии с нецензурной лексикой и оскорблениями удаляются

Второй день подряд проблемы в системе. И зайти не возможно, и если все же удалось, то каждое действие прогружается до минуты. Как работать-то?!

При возникновении ошибок, связанных с SAML (языком разметки декларации безопасности), следуйте инструкциям ниже.

Как кодировать или декодировать запросы и ответы SAML

Ошибки при добавлении приложения SAML

При добавлении приложения SAML в консоль администратора может возникнуть ошибка 400.

400 неуникальный идентификатор объекта

Используйте уже настроенное приложение или укажите другой идентификатор объекта.

500 ошибки при создании приложения SAML

При добавлении SAML-приложения в консоли администратора вы можете столкнуться с ошибками 500. Они появляются в следующих случаях:

Чтобы устранить ошибки 500 при добавлении SAML-приложения:

При возникновении этих проблем подождите немного и повторите попытку. Если ошибку устранить не удалось, обратитесь в службу поддержки Google Cloud.

Ошибки выполнения SAML

Если в ходе процессов, запущенных поставщиком услуг или поставщиком услуг идентификации (IdP), вы использовали систему единого входа на базе SAML, могут возникнуть следующие ошибки:

403 app_not_configured (приложение не настроено)

Эта ошибка может появиться в следующих случаях:

Приложение, соответствующее указанному в запросе идентификатору объекта, не было добавлено в консоль администратора.

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

  1. Убедитесь, что приложение, соответствующее идентификатору объекта в запросе, было установлено до отправки этого запроса.
  2. Удостоверьтесь, что идентификатор объекта в запросе SAML указан правильно и соответствует выбранному приложению.
  3. Убедитесь, что идентификатор поставщика услуг в URL запроса соответствует значению, указанному для приложения.

403 app_not_configured_for_user (приложение не настроено для пользователя)

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

Убедитесь, что значение тега saml:Issuer в запросе SAML совпадает со значением идентификатора объекта, заданным для SAML-приложения в разделе Сведения о поставщике услуг консоли администратора. Значение чувствительно к регистру.

403 app_not_enabled_for_user (приложение не включено для пользователя)

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

На главной странице консоли администратора нажмите ПриложенияМобильные и веб-приложения.

400 saml_invalid_user_id_mapping (неправильное сопоставление имени пользователя в SAML)

Если в запросе SAML поставщик услуг отправил параметр Идентификатор названия, он должен соответствовать значению, указанному на стороне поставщика идентификационной информации. В противном случае система выдаст ошибку.

  1. Откройте раздел Основные сведения и проверьте параметр Идентификатор названия.
  2. Убедитесь, что он соответствует значению запроса SAML, указанному на стороне поставщика идентификационной информации.

400 saml_invalid_sp_id (SAML неправильный идентификатор поставщика услуг)

Ошибка возникает, если идентификатор поставщика услуг в URL указан неверно, так как был некорректно настроен или подменен.

Откройте раздел Основные сведения и проверьте идентификатор приложения.

Убедитесь, что идентификатор поставщика услуг в URL запроса соответствует значению, указанному для приложения.

Недопустимый запрос от поставщика услуг, URL ACS в запросе не соответствует настроенному

Эта ошибка означает, что URL ACS в запросе SAML не соответствует значению , указанному для приложения в консоли администратора.

Перейдите в раздел Сведения о поставщике услуг.

Введите URL ACS, который указан в запросе SAML.

Недопустимый идентификатор поставщика услуг идентификационной информации в URL

Указанный в URL идентификатор поставщика идентификационной информации (зашифрованный идентификатор клиента) был искажен и является некорректным.

Перейдите в раздел БезопасностьНастройка системы единого входа для SAML-приложений.

В конце URL идентификатора объекта найдите идентификатор поставщика услуг идентификационной информации.

Недопустимый идентификатор поставщика услуг идентификации в запросе

URL системы единого входа со стороны поставщика услуг идентификации был искажен. Идентификатор поставщика скрытым образом изменен на идентификатор другого клиента.

Перейдите в раздел БезопасностьНастройка системы единого входа для SAML-приложений.

В конце URL идентификатора объекта найдите идентификатор поставщика услуг идентификационной информации.

Ошибки 500 при тестировании системы единого входа на базе SAML

Когда пользователи выполняют аутентификацию в системе единого входа на базе SAML через поставщика услуг или поставщика услуг идентификационной информации, они могут столкнуться с одной из ошибок 500 из-за недоступности сервера.

Чтобы устранить ошибки 500 при тестировании системы единого входа на базе SAML:

При возникновении этих ошибок подождите немного и повторите попытку. Если неполадку устранить не удалось, обратитесь в службу поддержки Google Cloud.

1000 ошибка доступа к приложению SAML

1000 ошибка доступа к настройкам приложения SAML

Эта ошибка возникает, если вы пытаетесь удалить специальную схему, которая выполняет роль сопоставления атрибутов для удаленного SAML-приложения. Ошибка 400 может возникать, если вы создали схему до устранения этой проблемы.

Интеграция с ЕСИА

При выполнении очередного госзаказа наша команда столкнулась с проблемой интеграции сайта с ЕСИА. Инструкции по решению этой задачи в сети нет, кроме информации в официальных документах МинКомСвязи (примерно 300 страниц в трех регламентах). Также есть компании, которые оказывают платные услуги по интеграции ЕСИА. Мы реализовали, описали процесс интеграции и решили поделиться с сообществом habrahabr.

Что такое ЕСИА

Единая Система Идентификации и Аутентификации — российская информациия система, обеспечивающая доступ (регистрация, аутентификация) на сайты государтсвенных структур и некоторых коммерческих организаций. Подробнее на википедии

В процессе интеграции ЕСИА, система сможет отправлять запрос на ЕСИА и при успешной авторизации получать в качестве ответа данные пользователя

Сценарий авторизации выглядит примерно так:

Содержание

  1. Общие сведения
  2. Установка SimpleSAMLphp
  3. Настройка SimpleSAMLphp для подключения к тестовой среде ЕСИА
  4. Конфигурация файла метаданных
  5. Отправка заявки в адрес МинКомСвзяи на подключение ИС к тестовой среде ЕСИА
  6. Функциональная интеграция с ЕСИА и получение данных авторизированных пользователей через ЕСИА
  7. Отправка заявки на подключение ИС к продуктивной среде ЕСИА

Общие сведения

Подключить ИС к ЕСИА возможно двумя способами:

  • Посредством стандарта SAML 2.0
  • На базе подхода REST

Если сравнивать 2 подхода, то по факту разницы между ними большой нет, есть несколько плюсов у способа на базе подхода REST. Есть ребята, которые на мой взгляд за немалые деньги подключают ЕСИА и о преимуществах REST они написали тут.

Но для подавляющего большинста случаев первый подход охватывает все необходимые функции. Поэтому расскажу о внедрении ЕСИА посредством SAML 2.0

Установка SimpleSAMLphp

Для интеграции будем использовать SimpleSAMLphp. Если система, которую вы настраиваете написана не на PHP, то все равно можно использовать этот модуль, просто на вашем сайте будет функция аутентификации реализована на php, данные от ЕСИА вы получите в xml формате.

Последняя официальная версия SimplSAMLphp доступна на официальном сайте SimpleSamlPHP. Скачиваете архив, распаковываете модуль в папку /var.В целях безопасности для папки с разархивированным модулем необходимо настроить права доступа только для root пользователя. В конфигурации сервера необходимо добавить алиас и следующие правила:

Суть в том, чтобы по запросу ServerName/simplesaml открывалась приветственная страница simplesaml. Если вы все сделали правильно, то по запросу ServerName/simplesaml вы увидите такую страничку

Настройка SimpleSAMLphp для подключения к тестовой среде ЕСИА

Для интеграции необходимы сертификат ( cert.crt ) и ключ ( key.key ). Важно(!) с ГОСТовским сертфикатом ничего не выйдет, можно получить бесплатный сертификат, погуглив как это делается, либо выпустить сертификат самому. Ключ и сертификат кладем в папку simplesamlphp/cert

Для конфигурации SimpleSAMLphp необходимо отредактировать следующие файлы:

  • simplesamlphp/config/config.php
  • simplesamlphp/config/authsources.php
  • simplesamlphp/metadata/saml20-idp-remote.php

Важное замечание — время на сервере не должно отличаться от времени ЕСИА больше 1 минуты.

Важно знать, есть ли у системы entityID, если его нет, то в поле ‘entityID’ необходимо указать адрес системы

Теперь надо получить подпись для нашего сертификата (fingerprint). Это можно сделать в терминале одной из команд

  • openssl x509 -noout -fingerprint -in «cert.crt» SHA1
  • sha1sum cert.crt

Конфигурация файла метаданных

Файл метаданных доступен по ссылке: ServerName/simplesaml/module.php/saml/sp/metadata.php/esia?output=xhtml

Пример файла метаданных:

Но, к сожалению, SimpleSaml формирует файл метаданных, который немного отличается от требования ЕСИА, поэтому необходимо его подкорретировать в соотвествии с рекомендациями пункт А.6 Шаблон файла метаданных

Пример файла метаданных, удовлетворяющий требованиям ЕСИА, может скачать по ссылке example.xml

Отправка заявки в адрес МинКомСвзяи на подключение ИС к тестовой среде ЕСИА

  • скан заявки в формате pdf,
  • сертификат в формате crt
  • файл метаданных xml

Функциональная интеграция с ЕСИА и получение данных авторизированных пользователей через ЕСИА

Проверить подключения ИС к тестовой среде можно по ссылке
ServerName/simplesaml/module.php/core/authenticate.php?as=esia .

xml ответ ЕСИА

Теперь напишем скрипт, который будет обрабатывать данные. Для начала добавим кнопку для авторизации на сайт.

Обработчик inc/esia.php . Тут мы получаем данные и можем записать их в базу, добавить в сессию и т.д. Вообще надо правильно парсить xml. Сейчас просто выведем данные на экран.

Отправка заявки на подключение ИС к продуктивной среде ЕСИА

В файлах simplesamlphp/config/authsources.php , simplesamlphp/metadata/saml20-idp-remote.php необходимо заменить idp поставщика услуг с Тестовой среды на продуктивную:

Теперь формируем новый файл метаданных, по факту меняются только ссылки в полях Service

  • Новый файл метаданных
  • Заявку по форме М

На момент написания статьи актуальная версии Регламента — 2.7. При обновлении регламента возможны некоторые изменения во взаимодействии ИС с ЕСИА.

Ниже приведены ответы на распространённые вопросы, которые возникают у пользователей при настройке и обслуживании Smartsheet, а также при входе с использованием функции единого входа на базе SAML. Узнайте больше о настройке и поддержке SAML в статье Обзор SAML и функции единого входа для Smartsheet.

Ниже перечислено несколько возможных причин.

  • В вашем браузере сохранены устаревшие данные для входа. Очистите кэш и файлы cookie в браузере и попробуйте войти снова.
  • Возможно, профиль поставщика удостоверений, используемый вами для проверки подлинности, еще не добавлен, или требуется его обновление. Попросите администратора поставщика удостоверений или ИТ-специалистов своей организации проверить, поступила ли информация о вашем профиле поставщику удостоверений.
  • Возможно, вас не добавили в учётную запись, с которой связан ваш домен. Попросите своего системного администратора добавить вас в учётную запись.

Вы можете обновить информацию о своих сертификатах в Smartsheet с помощью процедуры, описанной в статье Замена просроченного SAML-сертификата поставщика удостоверений. Учтите, что перед внесением изменений в Smartsheet у вас уже должен быть новый сертификат, сгенерированный вашим поставщиком удостоверений.

  • Убедитесь, что устройство, с которого вы пытаетесь войти, подключено к внутренней сети вашей компании.
  • Если для подключения к корпоративной сети вы используете VPN, убедитесь, что этот сервис запущен и подключение установлено.

Почему мне недоступна функция обновления метаданных поставщика удостоверений в Smartsheet?

Если вы используете тот же идентификатор сущности в другой учётной записи Smartsheet, вы не сможете изменить эти метаданные. Системный администратор второй учётной записи Smartsheet должен выполнить процедуру Замена просроченного SAML-сертификата поставщика удостоверений, чтобы обновить метаданные для всех её пользователей.

Уточнить администратора второй учётной записи Smartsheet можно в нашей службе поддержки.

На этом этапе ошибка вызвана соответствующими проблемами в метаданных. Ниже приведено несколько примеров возможных ошибок.

  • Не удалось выполнить проверку DNS. Убедитесь в том, что запись DNS распространилась, и повторите попытку.
  • Домен уже связан с поставщиком удостоверений
  • Отсутствуют метаданные SAML

Свяжитесь с администратором поставщика удостоверений и попросите его настроить запросы метаданных, а затем повторите процедуру настройки SAML. Пример утверждения и полный список поддерживаемых форматов запросов см. в статье Примеры настроек и запросов для протокола SAML в Smartsheet.

Как добавить домен поставщику удостоверений в Smartsheet?

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

BlooDy писал(а): Пишу чисто поржать, сегодня приверно в 5:30-5:45 по мск, все заработало. Я немного ох***л от такого счастья, что же думаю за ночь такого случилось. Решил проверить, сохранил настройки, скинул все настройки IE11 в дефолт, даже удалил закупки.гов.ру из доверенных, и о чудо, работает. Без настроек IE СОВСЕМ!

P.S. Е**ло мне голову начальство целую неделю этим, я е**л голову себе, а оказалось просто у рукожопов что-то не работало(не было обновлено и т.д.), и ладно бы сказать типа потерпите ребята о проблеме знаем — занимаемся. Делал 4 заявки в саппорт, ничего кроме «еще раз проверьте/скиньте настройки IE» не услышал. Мало того они эти заявки даже не читают, отписывают боты видимо пользователям. Писал в заявке «антивирус удален», в ответе — отключите антивирус Это просто пи***ц

Машины времени есть у каждого. Те, что переносят в прошлое, зовутся воспоминаниями, а те, что уносят в будущее — мечтами ©

APXAPOBETC писал(а): Тоже сейчас пытаюсь зарегистрироваться, впервые, в качестве ИП. В самом начале, на этапе подтверждения того, что я действительно хочу зарегистрироваться, меня выбрасывает на страницу ошибки: «Не удается открыть эту страницу. Убедитесь, что веб-адрес https://eruz.zakupki.gov.ru правильный». Поддержка ЕИС ничего не отвечает пока что, жду. Торги стоят ((( Использую IE11. Может, кто-то сталкивался с таким?

Временное явление, скорее всего. Надеюсь, уже исправили.
Если нет, то проверяйте, что у Вас указано в адресах DNS-серверов и как эти сервера работают. Возможно, глючит локальная сеть.

Машины времени есть у каждого. Те, что переносят в прошлое, зовутся воспоминаниями, а те, что уносят в будущее — мечтами ©

Ошибка регистрации сертификата по госту 2012

Добрый день, коллега.
Вам бы азы работы в ЕИС поизучать, дабы таких глупостей не совершать.
Сертификат регистрируется в администрировании, а не при входе. При входе было аж 4 года назад.
Читайте FAQ в данном разделе.

П.С. Надеюсь, Вы прохожий заказчик, а не прохожий поставщик.

Машины времени есть у каждого. Те, что переносят в прошлое, зовутся воспоминаниями, а те, что уносят в будущее — мечтами ©

Читайте также:

  • Подготовьте и запишите сообщение о том какие способы использовали люди для общения
  • В какой сфере легче сделать карьеру сообщение
  • Основание баргузинского острога сообщение
  • Вымершие животные по вине человека сообщение
  • Сообщение о новочебоксарске кратко

This page provides a general overview of the Security Assertion Markup Language (SAML) 2.0 Building Block along with common Single Sign-On (SSO) issues and troubleshooting techniques for the SAML authentication provider.

If for any reason an updated/new IdP metadata XML file is uploaded in the Blackboard Learn GUI on the SAML Authentication Settings page in the Identity Provider Settings section for a SAML authentication provider, the SAML B2 and that SAML authentication provider should also be toggled Inactive/Available, while having the SAML authentication provider in ‘Active’ status, to ensure any cached IdP metadata is cleared out and the updated IdP metadata is fully utilized.


Key terms

The following terms and abbreviations are used throughout this guide:

  • SAML: Security Assertion Markup Language
  • IdP: Identity Provider
  • SP: Service Provider
  • ADFS: Active Directory Federation Services
  • GUI: Graphical User Interface. In the context of Blackboard Learn, this means working within the software.

Edit SAML configuration settings

To help troubleshoot SAML authentication issues, the SAML Building Block was updated in release 3200.2.0 to include these configuration settings and options:

  • Define the SAML session age limit
  • Choose a signature algorithm type
  • Regenerate certificates
  • Change the ResponseSkew value

More on how to configure settings in the SAML Building Block


Errors and exceptions

SAML related errors/exceptions are captured in the following logs:

  • /usr/local/blackboard/logs/bb-services-log.txt
  • /usr/local/blackboard/logs/tomcat/stdout-stderr-<date>.log
  • /usr/local/blackboard/logs/tomcat/catalina-log.txt

These logs should always be searched when investigating a reported SAML authentication issue.


SAML Tracer

With SAML 2.0 authentication troubleshooting iterations, at some point it may be necessary to confirm/view the attributes that are actually being released from the IdP and sent to Learn during the authentication process. If the attributes from the IdP are NOT encrypted in the SAML response, the Firefox browser SAML tracer Add-on or Chrome SAML Message Decoder can be used to view the attributes.


Attribute not properly mapped

If the attribute containing the userName is not properly mapped as specified in the Remote User ID field in the Map SAML Attributes section on the SAML Authentication Settings page in the Blackboard Learn GUI, the following event will be logged in the bb-services log when attempting to login to Blackboard Learn via SAML authentication:

2016-06-28 12:48:12 -0400 — userName is null or empty

A similar Sign On Error! message displayed in the browser: Blackboard Learn is currently unable to log into your account using single-sign on. Contact your administrator for assistance.

An image of a Sign On Error message displayed in the browser that says Blackboard Learn is currently unable to log into your account using single-sing on. Contact your administrator for assistance.

An Authentication Failure entry appears in the bb-services log:

2016-06-28 12:48:12 -0400 — BbSAMLExceptionHandleFilter — javax.servlet.ServletException: Authentication Failure
    at blackboard.auth.provider.saml.customization.handler.BbAuthenticationSuccessHandler.checkAuthenticationResult(BbAuthenticationSuccessHandler.java:81)
    at blackboard.auth.provider.saml.customization.handler.BbAuthenticationSuccessHandler.onAuthenticationSuccess(BbAuthenticationSuccessHandler.java:57)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.successfulAuthentication(AbstractAuthenticationProcessingFilter.java:331)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:245)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
[SNIP]

Resolution

You have two options to resolve the issue. First, select the Create accounts if they don’t exist in the system option on the SAML Authentication Settings page in the Blackboard Learn GUI. Alternatively, you can attempt to view the value of the attributes released by the IdP via SAML tracer or Debug Logging if the attributes are NOT encrypted:

<saml2:Attribute Name=»urn:oid:0.9.2342.19200300.100.1.3″>
    <saml2:AttributeValue xmlns:xs=»http://www.w3.org/2001/XMLSchema»
                          xmlns:xsi=»http://www.w3.org/2001/XMLSchema-instance»
                          xsi:type=»xs:anyType»
                          >bbuser_saml2@bbchjones.net</saml2:AttributeValue>
</saml2:Attribute>

and map the Attribute Name that has the desired AttributeValue to the Remote User ID on the SAML Authentication Settings page in the Blackboard Learn GUI.


Compatible data source not selected

Users won’t be able to login to Blackboard Learn via SAML authentication if the Data Source for the users is not selected in the Services Provider Settings > Compatible Data Sources section on the SAML Authentication Settings page in the Blackboard Learn GUI. The following event will be logged in the bb-services log when attempting to log in to Blackboard Learn via SAML authentication:

2016-09-23 12:33:13 -0500 — userName is null or empty

The Sign On Error! message appears in the browser, as well as the Authentication Failure in the bb-services log:

2016-09-23 12:33:13 -0500 — BbSAMLExceptionHandleFilter — javax.servlet.ServletException: Authentication Failure
    at blackboard.auth.provider.saml.customization.handler.BbAuthenticationSuccessHandler.checkAuthenticationResult(BbAuthenticationSuccessHandler.java:82)
    at blackboard.auth.provider.saml.customization.handler.BbAuthenticationSuccessHandler.onAuthenticationSuccess(BbAuthenticationSuccessHandler.java:58)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.successfulAuthentication(AbstractAuthenticationProcessingFilter.java:331)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:245)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter (SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at sun.reflect.GeneratedMethodAccessor3399.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
        [SNIP]

Resolution

  1. Obtain the username of a user that is unable to login.
  2. In the Blackboard Learn GUI, navigate to System Admin > Users and search for the user.
  3. Copy the Data Source Key of the user.
  4. Navigate to System Admin > Authentication > «Provider Name» > SAML Settings > Compatible Data Sources.
  5. Place a check mark next to that Data Source in the Name column and select Submit.

«Given URL is not well formed» error message

If OneLogin is configured as the IdP for the SAML authentication provider in Blackboard Learn, a Given URL is not well formed error may be displayed on the page after entering the OneLogin credentials when attempting login to Blackboard Learn.

With the following displayed in the bb-services-log:

2016-09-16 09:43:40 -0400 — Given URL is not well formed<P><span class=»captionText»>For reference, the Error ID is 17500f44-7809-4b9f-a272-3bed1d1af131.</span> — java.lang.IllegalArgumentException: Given URL is not well formed
    at org.opensaml.util.URLBuilder.<init>(URLBuilder.java:120)
    at org.opensaml.util.SimpleURLCanonicalizer.canonicalize(SimpleURLCanonicalizer.java:87)
    at org.opensaml.common.binding.decoding.BasicURLComparator.compare(BasicURLComparator.java:57)
    at org.opensaml.common.binding.decoding.BaseSAMLMessageDecoder.compareEndpointURIs(BaseSAMLMessageDecoder.java:173)
    at org.opensaml.common.binding.decoding.BaseSAMLMessageDecoder.checkEndpointURI(BaseSAMLMessageDecoder.java:213)
    at org.opensaml.saml2.binding.decoding.BaseSAML2MessageDecoder.decode(BaseSAML2MessageDecoder.java:72)
    at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:105)
    at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:172)
    at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:80)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    [SNIP]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.net.MalformedURLException: no protocol: {recipient}
    at java.net.URL.<init>(URL.java:593)
    at java.net.URL.<init>(URL.java:490)
    at java.net.URL.<init>(URL.java:439)
    at org.opensaml.util.URLBuilder.<init>(URLBuilder.java:77)
        … 203 more

Resolution

  1. Turn on the Firefox browser SAML tracer and replicate the login issue.
  2. Review the beginning of the SAML POST event:

    <samlp:Response Destination=»{recipient}»
            ID=»R8afbfbfee7292613f98ad4ec4115de7c6b385be6″
            InResponseTo=»a3g2424154bb0gjh3737ii66dadbff4″
            IssueInstant=»2016-09-16T18:49:09Z»
            Version=»2.0″
            xmlns:saml=»urn:oasis:names:tc:SAML:2.0:assertion»
            xmlns:samlp=»urn:oasis:names:tc:SAML:2.0:protocol»
            >
        <saml:Issuer>https://app.onelogin.com/saml/metadata/123456</saml:Issuer>
        [SNIP]

  3. For line 1 with the Response, observe that the Destination= is only set to recipient.
  4. Have the client access the Configuration section of their OneLogin IdP.
  5. Confirm if the Recipient field is blank.
  6. Copy the value of the ACS (Consumer) URL, paste it into the Recipient field and select Save.

IdP/SP Problem Scenarios

  1. If an error appears before you are redirected to the IdP’s login page, the IdP’s metadata may be invalid.
  2. If an error appears after you log in on the IdP’s page, the reasons could be that:
    1. Attribute mapping between the SP and IdP is incorrect, or the IdP didn’t return a valid Remote User ID.
    2. The SAML response from the IdP wasn’t validated by the SP. This could be caused by:
      • The IdP signs the SAML response with a certificate that is not issued by a valid certificate authority, and the SP’s keystore doesn’t contain this certificate.
      • The SP’s system clock is incorrect.

Active Directory Federation Services (ADFS)

The attribute names are case sensitive in the Map SAML Attributes section on the SAML Authentication Settings page in the Blackboard Learn GUI. So if the Remote User ID has sAMAccountName for the Attribute Name on the settings page and the actual SAML POST from the IdP has this for the Attribute Name in the AttributeStatement:

<AttributeStatement>
    <Attribute Name=»SamAccountName>
        <AttributeValue>Test-User</AttributeValue>
    </Attribute>
</AttributeStatement>

The user will not be able to login. The Remote User ID attribute name value on the SAML Authentication Settings page would need to be changed from sAMAccountName to SamAccountName.

«Resource not found» or «Sign on error!» warning

This section contains some of the common problems that may prevent a user from logging into Learn via SAML authentication with ADFS when The specified resource was not found, or you do not have permission to access it or Sign On Error! message is displayed in the Blackboard Learn GUI.

Problem #1

After entering the login credentials on the ADFS login page, an error may be displayed after being redirected to the Blackboard Learn GUI: The specified resource was not found, or you do not have permission to access it.

A specified resource was not found error message

With a corresponding message in the stdout-stderr log:

INFO | jvm 1 | 2016/06/22 06:08:33 | — No mapping found for HTTP request with URI [/auth-saml/saml/SSO] in DispatcherServlet with name ‘saml’

The problem occurs because the noHandlerFound() method is used in the DispatcherServlet.java code and is unable to locate/map the HTTP SSO request.

/**
 * No handler found -> set appropriate HTTP response status.
 * @param request current HTTP request
 * @param response current HTTP response
 * @throws Exception if preparing the response failed
 */
protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
 if (pageNotFoundLogger.isWarnEnabled()) {
  pageNotFoundLogger.warn(«No mapping found for HTTP request with URI [» + getRequestUri(request) +
    «] in DispatcherServlet with name ‘» + getServletName() + «‘»);
 }
 if (this.throwExceptionIfNoHandlerFound) {
  throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request),
    new ServletServerHttpRequest(request).getHeaders());
 }
 else {
  response.sendError(HttpServletResponse.SC_NOT_FOUND);
 }
}

Resolution

This typically occurs because the Entity ID for the SP configured in the Blackboard Learn GUI is incorrect. This can be resolved by navigating to System Admin > Authentication > SAML Authentication Settings > Service Provider Settings and updating the Entity ID. For ADFS, the default configuration for the Entity ID would be https://[Learn Server Hostname]/auth-saml/saml/SSO.

If a school changes their URL from the default https://school.blackboard.com to https://their.school.edu, the Entity ID in the Blackboard Learn GUI on the SAML Authentication Settings page should be updated to https://their.school.edu/auth-saml/saml/SSO.

Problem #2

After entering the login credentials on the ADFS login page, an error may be displayed after being redirected to the Blackboard Learn GUI: The specified resource was not found, or you do not have permission to access it.

With this corresponding message in the stdout-stderr log:

INFO  | jvm 1  | 2016/06/22 06:08:33 | — No mapping found for HTTP request with URI [/auth-saml/saml/SSO] in DispatcherServlet with name ‘saml’

And this message in the catalina log:

ERROR 2016-06-27 10:47:03,664 connector-6: userId=_2_1, sessionId=62536416FB80462298C92064A7022E50 org.opensaml.xml.encryption.Decrypter — Error decrypting the encrypted data element
org.apache.xml.security.encryption.XMLEncryptionException: Illegal key size
Original Exception was java.security.InvalidKeyException: Illegal key size
    at org.apache.xml.security.encryption.XMLCipher.decryptToByteArray(XMLCipher.java:1822)
    at org.opensaml.xml.encryption.Decrypter.decryptDataToDOM(Decrypter.java:596)
    at org.opensaml.xml.encryption.Decrypter.decryptUsingResolvedEncryptedKey(Decrypter.java:795)
    at org.opensaml.xml.encryption.Decrypter.decryptDataToDOM(Decrypter.java:535)
    at org.opensaml.xml.encryption.Decrypter.decryptDataToList(Decrypter.java:453)
    at org.opensaml.xml.encryption.Decrypter.decryptData(Decrypter.java:414)
    at org.opensaml.saml2.encryption.Decrypter.decryptData(Decrypter.java:141)
    at org.opensaml.saml2.encryption.Decrypter.decrypt(Decrypter.java:69)
    at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:199)
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:82)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
        [SNIP]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.security.InvalidKeyException: Illegal key size
    at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1039)
    at javax.crypto.Cipher.init(Cipher.java:1393)
    at javax.crypto.Cipher.init(Cipher.java:1327)
    at org.apache.xml.security.encryption.XMLCipher.decryptToByteArray(XMLCipher.java:1820)
        … 205 more

And this message displayed in the bb-services log:

2016-06-27 10:47:03 -0400 — unsuccessfulAuthentication — org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
    at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at sun.reflect.GeneratedMethodAccessor3422.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:277)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:274)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
    at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:309)
    at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:249)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
    at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:55)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:191)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:187)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:186)
    at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:30)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at sun.reflect.GeneratedMethodAccessor3421.invoke(Unknown Source)
        [SNIP]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.opensaml.common.SAMLException: Response doesn’t have any valid assertion which would pass subject validation
    at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:229)
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87)
        … 229 more

The problem occurs because by default ADFS encrypts the attributes it sends using AES-256 and the Java runtime used by Blackboard Learn doesn’t support AES-256 out of the box.

Resolution

A universal resolution option is to open a PowerShell on the ADFS server and set the relying party created for Blackboard Learn to send the attributes as unencrypted. As the whole communication is over SSL, this will not reduce the security of the authentication. It also makes debugging of any issues easier as the attributes can be viewed using debugging tools such as the Firefox browser SAML tracer Add-on and a restart of the Blackboard Learn system is not required. To set the relying party created for Blackboard Learn to send the attributes as unencrypted, open a PowerShell and execute the following command, replacing TargetName with the name of the Relying Party Trust that is in the ADFS Management Console under Trust Relationships > Relying Party Trusts.

set-ADFSRelyingPartyTrust –TargetName «yourlearnserver.blackboard.com» –EncryptClaims $False

After this change the ADFS service will need to be restarted with the command: Restart-Service ADFSSRV

Problem #3

After entering the login credentials on the ADFS login page, an error may be displayed after being redirected to the Blackboard Learn GUI: The specified resource was not found, or you do not have permission to access it or Sign On Error!

With either, these similar corresponding SAML related events appear in the stdout-stderr log:

INFO   | jvm 1    | 2016/09/06 20:33:04 | — /saml/login?apId=_107_1&redirectUrl=https%3A%2F%2Fbb.fraser.misd.net%2Fwebapps%2Fportal%2Fexecute%2FdefaultTab at position 1 of 10 in additional filter chain; firing Filter: ‘SecurityContextPersistenceFilter’
INFO   | jvm 1    | 2016/09/06 20:33:04 | — No HttpSession currently exists
INFO   | jvm 1    | 2016/09/06 20:33:04 | — No SecurityContext was available from the HttpSession: null. A new one will be created.
INFO   | jvm 1    | 2016/09/06 20:33:04 | — /saml/login?apId=_107_1&redirectUrl=https%3A%2F%2Fbb.fraser.misd.net%2Fwebapps%2Fportal%2Fexecute%2FdefaultTab at position 2 of 10 in additional filter chain; firing Filter: ‘WebAsyncManagerIntegrationFilter’
INFO   | jvm 1    | 2016/09/06 20:33:04 | — /saml/login?apId=_107_1&redirectUrl=https%3A%2F%2Fbb.fraser.misd.net%2Fwebapps%2Fportal%2Fexecute%2FdefaultTab at position 3 of 10 in additional filter chain; firing Filter: ‘HeaderWriterFilter’
INFO   | jvm 1    | 2016/09/06 20:33:04 | — /saml/login?apId=_107_1&redirectUrl=https%3A%2F%2Fbb.fraser.misd.net%2Fwebapps%2Fportal%2Fexecute%2FdefaultTab at position 4 of 10 in additional filter chain; firing Filter: ‘FilterChainProxy’
INFO   | jvm 1    | 2016/09/06 20:33:04 | — Checking match of request : ‘/saml/login’; against ‘/saml/login/**’
INFO   | jvm 1    | 2016/09/06 20:33:04 | — /saml/login?apId=_107_1&redirectUrl=https%3A%2F%2Fbb.fraser.misd.net%2Fwebapps%2Fportal%2Fexecute%2FdefaultTab at position 1 of 1 in additional filter chain; firing Filter: ‘SAMLEntryPoint’
INFO   | jvm 1    | 2016/09/06 20:33:04 | — Request for URI http://www.w3.org/2000/09/xmldsig#rsa-sha1
INFO   | jvm 1    | 2016/09/06 20:33:04 | — Request for URI http://www.w3.org/2000/09/xmldsig#rsa-sha1
INFO   | jvm 1    | 2016/09/06 20:33:04 | — SecurityContext is empty or contents are anonymous — context will not be stored in HttpSession.
INFO   | jvm 1    | 2016/09/06 20:33:04 | — SecurityContextHolder now cleared, as request processing completed
INFO   | jvm 1    | 2016/09/06 20:33:07 | — /saml/SSO at position 1 of 10 in additional filter chain; firing Filter: ‘SecurityContextPersistenceFilter’
INFO   | jvm 1    | 2016/09/06 20:33:07 | — HttpSession returned null object for SPRING_SECURITY_CONTEXT
INFO   | jvm 1    | 2016/09/06 20:33:07 | — No SecurityContext was available from the HttpSession: [email protected] A new one will be created.
INFO   | jvm 1    | 2016/09/06 20:33:07 | — /saml/SSO at position 2 of 10 in additional filter chain; firing Filter: ‘WebAsyncManagerIntegrationFilter’
INFO   | jvm 1    | 2016/09/06 20:33:07 | — /saml/SSO at position 3 of 10 in additional filter chain; firing Filter: ‘HeaderWriterFilter’
INFO   | jvm 1    | 2016/09/06 20:33:07 | — /saml/SSO at position 4 of 10 in additional filter chain; firing Filter: ‘FilterChainProxy’
INFO   | jvm 1    | 2016/09/06 20:33:07 | — Checking match of request : ‘/saml/sso’; against ‘/saml/login/**’
INFO   | jvm 1    | 2016/09/06 20:33:07 | — Checking match of request : ‘/saml/sso’; against ‘/saml/logout/**’
INFO   | jvm 1    | 2016/09/06 20:33:07 | — Checking match of request : ‘/saml/sso’; against ‘/saml/bbsamllogout/**’
INFO   | jvm 1    | 2016/09/06 20:33:07 | — Checking match of request : ‘/saml/sso’; against ‘/saml/sso/**’
INFO   | jvm 1    | 2016/09/06 20:33:07 | — /saml/SSO at position 1 of 1 in additional filter chain; firing Filter: ‘SAMLProcessingFilter’
INFO   | jvm 1    | 2016/09/06 20:33:07 | — Authentication attempt using org.springframework.security.saml.SAMLAuthenticationProvider
INFO   | jvm 1    | 2016/09/06 20:33:07 | — Forwarding to /
INFO   | jvm 1    | 2016/09/06 20:33:07 | — DispatcherServlet with name ‘saml’ processing POST request for [/auth-saml/saml/SSO]
INFO   | jvm 1    | 2016/09/06 20:33:07 | — No mapping found for HTTP request with URI [/auth-saml/saml/SSO] in DispatcherServlet with name ‘saml’
INFO   | jvm 1    | 2016/09/06 20:33:07 | — SecurityContext is empty or contents are anonymous — context will not be stored in HttpSession.
INFO   | jvm 1    | 2016/09/06 20:33:07 | — Successfully completed request
INFO   | jvm 1    | 2016/09/06 20:33:07 | — Skip invoking on
INFO   | jvm 1    | 2016/09/06 20:33:07 | — SecurityContextHolder now cleared, as request processing completed

Or these similar SAML exceptions in the bb-services log:

2016-11-29 09:04:24 -0500 — unsuccessfulAuthentication — org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
    at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at sun.reflect.GeneratedMethodAccessor853.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:282)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:279)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
    at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314)
    at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
    at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:46)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:148)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:144)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:143)
    at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:30)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at sun.reflect.GeneratedMethodAccessor853.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        [SNIP]
    at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:677)
    at blackboard.tomcat.valves.LoggingRemoteIpValve.invoke(LoggingRemoteIpValve.java:44)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:1110)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:785)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1425)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.opensaml.common.SAMLException: Response issue time is either too old or with date in the future, skew 60, time 2016-11-29T14:03:16.634Z
    at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:126)
    at blackboard.auth.provider.saml.customization.consumer.BbSAMLWebSSOProfileConsumerImpl.processAuthenticationResponse(BbSAMLWebSSOProfileConsumerImpl.java:40)
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87)
        … 230 more

The problem occurs when the ADFS server and the Blackboard Learn application server have a time drift close to or beyond the default of 60 seconds.

Resolution

There are two options to resolve the issue:

  1. Manually syncing the clocks of the Blackboard Learn application servers and the ADFS server. For Blackboard Learn, the current time and time zone of the server can be viewed in a web browser by adding /webapps/portal/healthCheck to the end of a Blackboard Learn URL.

    Example: https://mhtest1.blackboard.com//webapps/portal/healthCheck

    Hostname: ip-10-145-49-11.ec2.internal
    Status: Active — Database connectivity established
    Running since: Sat, Dec 3, 2016 — 05:39:11 PM EST
    Time of request: Thu, Dec 8, 2016 — 05:12:43 PM EST

    An institution may use the above URL to compare the Blackboard Learn system time zone and clock with that of their ADFS server and then adjust those items as necessary on the ADFS server so that they are in-sync with the Blackboard Learn site.

Problem #4

After entering the login credentials on the ADFS login page, an error may be displayed after being redirected to the Blackboard Learn GUI: The specified resource was not found, or you do not have permission to access it or Sign On Error!

With the following exceptions in the bb-services log:

2016-11-01 12:47:19 -0500 — unsuccessfulAuthentication — org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
    at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at sun.reflect.GeneratedMethodAccessor929.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:282)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:279)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
    at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314)
    at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
    at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:46)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:148)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:144)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:143)
    at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:30)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
 [SNIP]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.opensaml.common.SAMLException: Response has invalid status code urn:oasis:names:tc:SAML:2.0:status:Responder, status message is null
    at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:113)
    at blackboard.auth.provider.saml.customization.consumer.BbSAMLWebSSOProfileConsumerImpl.processAuthenticationResponse(BbSAMLWebSSOProfileConsumerImpl.java:40)
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87)
        … 230 more
 2016-11-01 12:47:19 -0500 — BbSAMLExceptionHandleFilter — javax.servlet.ServletException: Unsuccessful Authentication
         at blackboard.auth.provider.saml.customization.filter.BbSAMLProcessingFilter.unsuccessfulAuthentication(BbSAMLProcessingFilter.java:31)
         at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:235)
         at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
         at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
         at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
         at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
         at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
         at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
         at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
         at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
         at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
         at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
         at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
         at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
         at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
         at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
         at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
         at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
         at sun.reflect.GeneratedMethodAccessor929.invoke(Unknown Source)
         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
         at java.lang.reflect.Method.invoke(Method.java:498)
         at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:282)
         at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:279)
         at java.security.AccessController.doPrivileged(Native Method)
         at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
         at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314)
         at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253)
         at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
         at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:46)
         at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:148)
         at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:144)
         at java.security.AccessController.doPrivileged(Native Method)
         at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:143)
         at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:30)
 [SNIP]

Resolution
  1. Navigate to the Admin Panel.
  2. Under Building Blocks, select Building Blocks.
  3. Select Installed Tools.
  4. Locate Authentication Provider — SAML in the list. Open the menu and select Settings.
  5. Under Signature Algorithm Settings, choose SHA-256 in the list. After you select the Signature Algorithm Type, restart the SAML building block to apply the new settings.
  6. Select Submit to save your changes.

Problem #5

After entering the login credentials on the ADFS login page, an error may be displayed after being redirected to the Blackboard Learn GUI: The specified resource was not found, or you do not have permission to access it or Sign On Error!

With the following exceptions in the bb-services log:

2017-01-04 22:52:58 -0700 — unsuccessfulAuthentication — org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
    at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at sun.reflect.GeneratedMethodAccessor935.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:282)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:279)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
    at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314)
    at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
    at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:46)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:148)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:144)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:143)
    at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:30)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    [SNIP]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.opensaml.common.SAMLException: NameID element must be present as part of the Subject in the Response message, please enable it in the IDP configuration
    at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:252)
    at blackboard.auth.provider.saml.customization.consumer.BbSAMLWebSSOProfileConsumerImpl.processAuthenticationResponse(BbSAMLWebSSOProfileConsumerImpl.java:40)
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87)
        … 214 more

As stated in the above SAML exception, the NameID element is missing from the Subject in the Response message. The problem typically occurs when the NameID is not setup as an Outgoing Claim Type in a Claims Rule for the Relying Party Trust on the institution’s ADFS IdP or the Claims Rule for the NameID is not in the proper order for the Relying Party Trust on the institution’s ADFS IdP, which in turn causes the missing NameID element in the Subject in the Response message.

Example: NameID element is missing

<Subject>
    <SubjectConfirmation Method=»urn:oasis:names:tc:SAML:2.0:cm:bearer»>
        <SubjectConfirmationData InResponseTo=»a22ai8iig0f75ae22hd28748b12da50″
                                 NotOnOrAfter=»2017-01-03T05:57:58.234Z»
                                 Recipient=»https://yourschool.blackboard.com/auth-saml/saml/SSO»
                                 />
    </SubjectConfirmation>
</Subject>

Example: NameID element is present

<Subject>
    <NameID Format=»urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress»>testadfs</NameID>
    <SubjectConfirmation Method=»urn:oasis:names:tc:SAML:2.0:cm:bearer»>
        <SubjectConfirmationData InResponseTo=»a5903d39if463ea87ieiab5135j9ji»
                                 NotOnOrAfter=»2017-01-05T04:33:12.715Z»
                                 Recipient=»https://yourschool.blackboard.com/auth-saml/saml/SSO»
                                 />
    </SubjectConfirmation>
</Subject>

You can use the Firefox SAML tracer Add-on to view the Subject in the Response message.

Resolution

There are three methods to resolving this issue.

  1. Confirm the steps from the SAML B2 Setup Guide for ADFS were properly followed and make changes as needed to transform an incoming claim for the Relying Party Trust for their ADFS IdP:
    1. Select Edit Claims Rule.
    2. Select Add Rule.
    3. On the Select Rule Template page, select Transform an Incoming Claim for the Claim rule template and then select Next.
    4. On the Configure Rule page, in the Claim rule name field, type Transform Email to Name ID.
    5. Incoming claim type should be SamAccountName (it must match the Outgoing Claim Type created initially in the Transform Username to NameID rule).
    6. The Outgoing claim type is Name ID.
    7. The Outgoing name ID format is Email.
    8. Confirm Pass through all claim values is selected and select Finish.
    9. Select OK to save the rule and OK again to complete the attribute mappings.
  2. Ensure for the order of the Claims Rules used for their ADFS IdP that the rule which has the NameID element does not have any optional rules occurring before it.
  3. If using a custom attribute, ensure the NameID element is in the Relying Party Trust since Learn still expects that their ADFS IdP release a NameID value.

Problem #6

When logged into Blackboard Learn via SAML authentication, the user attempts to log out by clicking on the Sign Out button on the left side of the page and then clicks the End SSO Session button, a Sign On Error! is immediately displayed.

Sign On Error!
Blackboard Learn is currently unable to log into your account using single sign-on. Contact your administrator for assistance.
For reference, the Error ID is [error ID].

With the following exception in the bb-services log:

2017-05-08 15:10:46 -0400 — BbSAMLExceptionHandleFilter Error Id: f3299757-8d4e-4fab-98cf-49cd99f4891e — javax.servlet.ServletException: Incoming SAML message failed security validation
    at org.springframework.security.saml.SAMLLogoutProcessingFilter.processLogout(SAMLLogoutProcessingFilter.java:145)
    at org.springframework.security.saml.SAMLLogoutProcessingFilter.doFilter(SAMLLogoutProcessingFilter.java:104)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    [SNIP]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.opensaml.ws.security.SecurityPolicyException: Validation of request simple signature failed for context issuer
    at org.opensaml.common.binding.security.BaseSAMLSimpleSignatureSecurityPolicyRule.doEvaluate(BaseSAMLSimpleSignatureSecurityPolicyRule.java:139)
    at org.opensaml.common.binding.security.BaseSAMLSimpleSignatureSecurityPolicyRule.evaluate(BaseSAMLSimpleSignatureSecurityPolicyRule.java:103)
    at org.opensaml.ws.security.provider.BasicSecurityPolicy.evaluate(BasicSecurityPolicy.java:51)
    at org.opensaml.ws.message.decoder.BaseMessageDecoder.processSecurityPolicy(BaseMessageDecoder.java:132)
    at org.opensaml.ws.message.decoder.BaseMessageDecoder.decode(BaseMessageDecoder.java:83)
    at org.opensaml.saml2.binding.decoding.BaseSAML2MessageDecoder.decode(BaseSAML2MessageDecoder.java:70)
    at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:105)
    at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:172)
    at org.springframework.security.saml.SAMLLogoutProcessingFilter.processLogout(SAMLLogoutProcessingFilter.java:131)
    … 244 more

The error occurs because of the Single Logout Service Type setting on the SAML Settings page.

Resolution

The setting needs to be configured in Blackboard Learn and on the ADFS server.

For ADFS as the IdP, select the Post setting only and remove the Redirect endpoint for the Learn instance’s Relying Party Trust on the ADFS server.

  1. In Learn, navigate to Admin > Authentication > (Provider Name) > SAML Settings > Single Logout Service Type.
  2. Select Post and clear the Redirect checkbox.
  3. In the ADFS Server, go into the Relying Party Trust for your Learn Instance.
  4. Select Properties > Endpoints. Two SAML logout endpoints are listed.
  5. Remove the Redirect endpoint. Select Remove Endpoint to remove it, then Apply and OK.

After making the above changes in Learn and the ADFS server, the End SSO Session logout button will work to properly sign out the user.

Problem #7

After entering the login credentials on the ADFS login page, a Sign On Error! message is displayed when redirected to Learn.

With the following SAML exception in the bb-services log:

2017-05-26 07:39:30 -0400 — unsuccessfulAuthentication — org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
        at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100)
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
        at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
        at blackboard.auth.provider.saml.customization.filter.BbSAMLProcessingFilter.attemptAuthentication(BbSAMLProcessingFilter.java:46)
        at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
        at sun.reflect.GeneratedMethodAccessor380.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:282)
        at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:279)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
        at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314)
        at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
        at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:46)
        at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:148)
        at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:144)
        at java.security.AccessController.doPrivileged(Native Method)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:143)
        at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:37)
    [SNIP]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)
Caused by: org.opensaml.common.SAMLException: Response has invalid status code urn:oasis:names:tc:SAML:2.0:status:Responder, status message is null
        at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:113)
        at blackboard.auth.provider.saml.customization.consumer.BbSAMLWebSSOProfileConsumerImpl.processAuthenticationResponse(BbSAMLWebSSOProfileConsumerImpl.java:56)
        at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87)
        … 247 more

Resolution

Beginning in Blackboard Learn 3200.0.0, there is now an option to regenerate the SAML encryption certificate by navigating to System Admin > Building Blocks > Authentication Provider — SAML > Settings > Regenerate Certificate. The Sign On Error! problem may occur if the Regenerate certificate button is selected after the SP metadata is already uploaded to the Relying Party Trust for the Learn site on the ADFS server. To resolve the issue:

  1. Navigate to System Admin > Authentication > [SAML Provider Name] > SAML Settings.
  2. Select Generate next to Service Provider Metadata to save the new metadata file.
  3. Access your ADFS server and upload the new SP metadata to the Relying Party Trust for your Learn site.

If you generate a new certificate under the B2 settings, you need to toggle the SAML B2 to Inactive and then back to Active to force the change. After, you can return to the provider settings and generate the new metadata to import into the IDP. If you don’t toggle the settings, the old certificate may still be included when you generate new metadata. The IDP won’t be updated and the next time Learn restarts it will present the new certificate. SAML authentication will break because of this mismatch.

Federation Metadata

With Active Directory Federation Services (ADFS), since the metadata for an ADFS federation typically located in https://[ADFS Server Hostname]/FederationMetadata/2007-06/FederationMetadata.xml includes an element that is incompatible with SAML 2.0, the metadata needs to be edited to delete the incompatible element before it is uploaded to the Identity Provider Settings section on the SAML Authentication Settings page in the Blackboard Learn GUI. If the metadata with the incompatible element is uploaded, an error will occur when selecting the SAML login link on the Blackboard Learn login page: Metadata for entity [entity] and role {} wasn’t found. For reference, the Error ID is [error ID].

And the corresponding Java stack trace for the Error ID in the bb-services log has the following:

2016-06-21 11:42:51 -0700 — Metadata for entity https://<Learn Server Hostname>/adfs/ls/ and role {urn:oasis:names:tc:SAML:2.0:metadata}SPSSODescriptor wasn’t found<P><span class=»captionText»>For reference, the Error ID is c99511ae-1162-4941-b823-3dda19fea157.</span> — org.opensaml.saml2.metadata.provider.MetadataProviderException: Metadata for entity https://ulvsso.laverne.edu/adfs/ls/ and role {urn:oasis:names:tc:SAML:2.0:metadata}SPSSODescriptor wasn’t found
    at org.springframework.security.saml.context.SAMLContextProviderImpl.populateLocalEntity(SAMLContextProviderImpl.java:319)
    at org.springframework.security.saml.context.SAMLContextProviderImpl.populateLocalContext(SAMLContextProviderImpl.java:216)
    at org.springframework.security.saml.context.SAMLContextProviderImpl.getLocalAndPeerEntity(SAMLContextProviderImpl.java:126)
    at org.springframework.security.saml.SAMLEntryPoint.commence(SAMLEntryPoint.java:146)
    at org.springframework.security.saml.SAMLEntryPoint.doFilter(SAMLEntryPoint.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at sun.reflect.GeneratedMethodAccessor1652.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
        [SNIP]

Resolution

Since the default metadata location for an ADFS federation is https://[ADFS server hostname]/FederationMetadata/2007-06/FederationMetadata.xml:

  1. Download this file and open it in a text editor. Carefully delete the section starting <ds:Signature xmlns:ds=»http://www.w3.org/2000/09/xmldsig#»> … </X509Data></KeyInfo> and ending </ds:Signature>
    <ds:Signature xmlns:ds=»http://www.w3.org/2000/09/xmldsig#»>

    <ds:SignedInfo>
      <ds:CanonicalizationMethod Algorithm=»http://www.w3.org/2001/10/xml-exc-c14n#»/>
      <ds:SignatureMethod Algorithm=»http://www.w3.org/2001/04/xmldsig-more#rsa-sha256″/>
      <ds:Reference URI=»#_43879f32-9a91-4862-bc87-e98b85b51158″>
       <ds:Transforms>
        <ds:Transform Algorithm=»http://www.w3.org/2000/09/xmldsig#enveloped-signature»/>
        <ds:Transform Algorithm=»http://www.w3.org/2001/10/xml-exc-c14n#»/>
       </ds:Transforms>
       <ds:DigestMethod Algorithm=»http://www.w3.org/2001/04/xmlenc#sha256″/>
       <ds:DigestValue>z1H1[SNIP]jaYM=</ds:DigestValue>
      </ds:Reference>
      </ds:SignedInfo>
      <ds:SignatureValue> FVj[SNIP]edrfNKWvsvk5A==
      </ds:SignatureValue>
      <KeyInfo xmlns=»http://www.w3.org/2000/09/xmldsig#»>
       <X509Data>
        <X509Certificate>
        FDdd[SNIP]qTNKdk5F/vf1AocDaX
        </X509Certificate>
       </X509Data>
      </KeyInfo>
    </ds:Signature>

  2. Upload the updated metadata XML file in the Blackboard Learn GUI on the SAML Authentication Settings page in the Identity Provider Settings section.
  3. Toggle the SAML authentication provider and SAML B2 Inactive/Available, while having the SAML authentication provider in ‘Active’ status.

If an institution is testing SAML authentication on a Blackboard Learn site and has multiple SAML authentication providers that share the same underlying ADFS IdP metadata XML file on the Blackboard Learn site, even if the other SAML authentication providers are set to Inactive, they will also need to have the updated metadata XML file uploaded in the Blackboard Learn GUI on the SAML Authentication Settings page in the Identity Provider Settings section. The SAML B2 should then be toggled Inactive/Available, while having the SAML authentication provider in ‘Active’ status, to ensure the updated metadata XML file is recognized system-wide.

Incorrect user lookup method

After entering the login credentials on the ADFS login page, the user is redirected to the Blackboard Learn GUI, but not logged into Blackboard Learn.

The ONLY SAML authentication related event in the bb-services log is:

2016-10-18 13:03:28 -0600 — userName is null or empty

Resolution

  1. Login to Blackboard Learn as administrator using the default Blackboard Learn Internal authentication.
  2. Navigate to System Admin > «SAML Authentication Provider Name» > Edit.
  3. Change the User Lookup Method from Batch Uid to Username.

Extra End SSO Session logout button

ADFS tries to add an extra End SSO Session logout button on the End all sessions? page that is displayed after first selecting the logout button at the top right in the Blackboard Learn GUI.

This is done by adding an extra SingleLogoutService to the IdP Metadata file:

<SingleLogoutService Binding=»urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect» Location=»https://your.server.name/adfs/ls/»/>
<SingleLogoutService Binding=»urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST» Location=»https://your.server.name/adfs/ls/»/>

Since that is an optional SAML B2 IdP configuration and the signature being provided in the Redirect Endpoint is not correct, an error will occur when selecting the extra End SSO Session button on the End all sessions? page: Incoming SAML message failed security validation. Validation of request simple signature failed for context issuer. For reference, the error Id is [error ID].

The corresponding Java stack trace for the Error ID in the bb-services log has:

2016-10-17 16:57:44 -0400 — Incoming SAML message failed security validation Validation of request simple signature failed for context issuer<P><span class=»captionText»>For reference, the Error ID is 930c7767-8710-475e-8415-2077152280e0.</span> — org.opensaml.ws.security.SecurityPolicyException: Validation of request simple signature failed for context issuer
    at org.opensaml.common.binding.security.BaseSAMLSimpleSignatureSecurityPolicyRule.doEvaluate(BaseSAMLSimpleSignatureSecurityPolicyRule.java:139)
    at org.opensaml.common.binding.security.BaseSAMLSimpleSignatureSecurityPolicyRule.evaluate(BaseSAMLSimpleSignatureSecurityPolicyRule.java:103)
    at org.opensaml.ws.security.provider.BasicSecurityPolicy.evaluate(BasicSecurityPolicy.java:51)
    at org.opensaml.ws.message.decoder.BaseMessageDecoder.processSecurityPolicy(BaseMessageDecoder.java:132)
    at org.opensaml.ws.message.decoder.BaseMessageDecoder.decode(BaseMessageDecoder.java:83)
    at org.opensaml.saml2.binding.decoding.BaseSAML2MessageDecoder.decode(BaseSAML2MessageDecoder.java:70)
    at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:105)
    at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:172)
    at org.springframework.security.saml.SAMLLogoutProcessingFilter.processLogout(SAMLLogoutProcessingFilter.java:131)
    at org.springframework.security.saml.SAMLLogoutProcessingFilter.doFilter(SAMLLogoutProcessingFilter.java:104)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at sun.reflect.GeneratedMethodAccessor1652.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
        [SNIP]

Resolution

  1. Access the ADFS Server and go into the Relying Party Trust for the Blackboard Learn Instance.
  2. Select Properties > Endpoints tab.
  3. In the Endpoints tab there will be 2 SAML Logout Endpoints.
  4. Remove the Redirect endpoint.
  5. Select Remove Endpoint to remove it, then Apply and OK.

After removing the Redirect endpoint, the End SSO Session button will work properly signing out the user.

Viewing application logs with event viewer

When troubleshooting an ADFS SAML authentication issue, it may be necessary to also have an institution review the ADFS application logs in the Event Viewer on their ADFS server for further insight. This is particularly necessary when the SAML response from the ADFS server has a Request Denied status as seen below:

<samlp:Status>
    <samlp:StatusCode Value=»urn:oasis:names:tc:SAML:2.0:status:Responder»>
        <samlp:StatusCode Value=»urn:oasis:names:tc:SAML:2.0:status:RequestDenied» />
    </samlp:StatusCode>
</samlp:Status>

The SAML response can be viewed by using the Firefox browser SAML tracer Add-on.

The Request Denied status in a response typically indicates a problem occurred when the IdP (ADFS) attempted to understand the response and process the result the SP (Blackboard Learn) provided.

To view the ADFS application logs with the Event Viewer:

  1. Open the Event Viewer on the ADFS server.
  2. On the View menu, select Show Analytic and Debug Logs.
  3. In the console tree, navigate to Application and Service Logs > AD FS Tracing > Debug.

Azure Active Directory

Azure AD is Microsoft’s (MS) cloud based directory and identity management service.

Send first part of email

If an institution is using Azure AD as their IdP and wishes to only have the first part of the Azure AD email username used for the Blackboard Learn username, they can configure their Azure AD IdP to use the special ExtractMailPrefix() function to remove the domain suffix from either the email or the user principal name resulting in only the first part of the username being passed through (e.g. «joesmith» instead of joesmith@example.com).

If the Blackboard Learn Remote User ID is urn:oid:1.3.6.1.4.1.5923.1.1.1.6, the Attribute setting for the Azure IdP would look like this:

Attribute Name:        urn:oid:1.3.6.1.4.1.5923.1.1.1.6
Attribute Value:    ExtractMailPrefix()
Mail:            user.userprincipalname

So with the example joesmith@example.com email username, it would be passed like this in the SAML assertion from the Azure IdP to Blackboard Learn:

<Attribute Name=»urn:oid:1.3.6.1.4.1.5923.1.1.1.6″>
    <AttributeValue>joesmith</AttributeValue>

Additional info about using the ExtractMailPrefix() function is available on the MS Azure documentation page.

Azure AD IdP updating certificate

After entering the login credentials on the MS Azure AD login page, a Sign On Error! may be displayed after being redirected to the Blackboard Learn GUI.

With the following exception in the bb-services log:

2016-10-13 12:03:23 +0800 — unsuccessfulAuthentication — org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
 at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100)
 at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
 at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
 at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
 at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
 at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
 at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
 at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
 at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
 at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
 at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
 at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
 at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
 at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
 at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
 at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
 at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
 at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
 at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
 at sun.reflect.GeneratedMethodAccessor854.invoke(Unknown Source)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
 at java.lang.reflect.Method.invoke(Method.java:498)
 at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:282)
 at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:279)
 at java.security.AccessController.doPrivileged(Native Method)
 at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
 at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314)
 at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253)
 at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
 at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:46)
 at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:148)
 at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:144)
 at java.security.AccessController.doPrivileged(Native Method)
 at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:143)
 at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:30)
 [SNIP]
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
 at java.lang.Thread.run(Thread.java:745)
Caused by: org.opensaml.common.SAMLException: Response doesn’t have any valid assertion which would pass subject validation
 at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:229)
 at blackboard.auth.provider.saml.customization.consumer.BbSAMLWebSSOProfileConsumerImpl.processAuthenticationResponse(BbSAMLWebSSOProfileConsumerImpl.java:40)
 at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87)
 … 230 more
Caused by: org.opensaml.xml.validation.ValidationException: Signature is not trusted or invalid
 at org.springframework.security.saml.websso.AbstractProfileBase.verifySignature(AbstractProfileBase.java:272)
 at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAssertionSignature(WebSSOProfileConsumerImpl.java:419)
 at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAssertion(WebSSOProfileConsumerImpl.java:292)
 at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:214)
 … 232 more

This is caused by the MS Azure AD IdP updating the certificate, but the metadata XML used by the Blackboard Learn SP not being adjusted to reflect the new certificate.

Resolution

  • The new metadata XML file with the new certificate will need to be updated on the SAML Settings page in the Blackboard Learn GUI for the authentication provider.
  • The SAML B2 and the authentication provider will then need to be toggled Inactive/Available, while having the SAML authentication provider in ‘Active’ status, to have the updated metadata with the new certificate applied.
  • If a Blackboard Learn site has multiple authentication providers that share the same underlying certificate for the same underlying IdP Entity ID, ALL those authentication providers will need to be updated.

Microsoft has indicated that that they will be updating certificates every 6 weeks from now on, and that such updates will be unannounced.


IdP-initiated single sign on

If a user first logs into their user portal and then selects the app for their Blackboard Learn site, a new browser tab opens to display a message: The specified resource was not found, or you do not have permission to access it.

With the corresponding SAML related events in the stdout-stderr.log:

INFO   | jvm 1    | 2016/08/16 10:49:22 | — /saml/SSO at position 1 of 10 in additional filter chain; firing Filter: ‘SecurityContextPersistenceFilter’
INFO   | jvm 1    | 2016/08/16 10:49:22 | — HttpSession returned null object for SPRING_SECURITY_CONTEXT
INFO   | jvm 1    | 2016/08/16 10:49:22 | — No SecurityContext was available from the HttpSession: [email protected] A new one will be created.
INFO   | jvm 1    | 2016/08/16 10:49:22 | — /saml/SSO at position 2 of 10 in additional filter chain; firing Filter: ‘WebAsyncManagerIntegrationFilter’
INFO   | jvm 1    | 2016/08/16 10:49:22 | — /saml/SSO at position 3 of 10 in additional filter chain; firing Filter: ‘HeaderWriterFilter’
INFO   | jvm 1    | 2016/08/16 10:49:22 | — /saml/SSO at position 4 of 10 in additional filter chain; firing Filter: ‘FilterChainProxy’
INFO   | jvm 1    | 2016/08/16 10:49:22 | — Checking match of request : ‘/saml/sso’; against ‘/saml/login/**’
INFO   | jvm 1    | 2016/08/16 10:49:22 | — Checking match of request : ‘/saml/sso’; against ‘/saml/logout/**’
INFO   | jvm 1    | 2016/08/16 10:49:22 | — Checking match of request : ‘/saml/sso’; against ‘/saml/bbsamllogout/**’
INFO   | jvm 1    | 2016/08/16 10:49:22 | — Checking match of request : ‘/saml/sso’; against ‘/saml/sso/**’
INFO   | jvm 1    | 2016/08/16 10:49:22 | — /saml/SSO at position 1 of 1 in additional filter chain; firing Filter: ‘SAMLProcessingFilter’
INFO   | jvm 1    | 2016/08/16 10:49:22 | — Forwarding to /
INFO   | jvm 1    | 2016/08/16 10:49:22 | — DispatcherServlet with name ‘saml’ processing POST request for [/auth-saml/saml/SSO]
INFO   | jvm 1    | 2016/08/16 10:49:22 | — No mapping found for HTTP request with URI [/auth-saml/saml/SSO] in DispatcherServlet with name ‘saml’
INFO   | jvm 1    | 2016/08/16 10:49:22 | — SecurityContext is empty or contents are anonymous — context will not be stored in HttpSession.
INFO   | jvm 1    | 2016/08/16 10:49:22 | — Successfully completed request
INFO   | jvm 1    | 2016/08/16 10:49:22 | — Skip invoking on
INFO   | jvm 1    | 2016/08/16 10:49:22 | — SecurityContextHolder now cleared, as request processing completed

The Service Provider Settings section of the SAML Authentication Settings page has changed and the Enable automatic SSO option should be checked to allow a user to access Blackboard Learn from their portal. If it is enabled, the ACS URL will also be changed to include an alias.


Wrong document error

After entering the login credentials on the SAML authentication provider login page, a Sign On Error! may be displayed after being redirected to the Blackboard Learn GUI.

With the following DOMException and WRONG_DOCUMENT_ERR in the bb-services log:

2016-11-18 12:27:31 -0600 — WRONG_DOCUMENT_ERR: A node is used in a different document than the one that created it.<P><span class=»captionText»>For reference, the Error ID is 86ebb81d-d3a3-4da5-95ab-1c94505f4281.</span> — org.w3c.dom.DOMException: WRONG_DOCUMENT_ERR: A node is used in a different document than the one that created it.
    at org.apache.xerces.dom.ParentNode.internalInsertBefore(Unknown Source)
    at org.apache.xerces.dom.ParentNode.insertBefore(Unknown Source)
    at org.apache.xerces.dom.NodeImpl.appendChild(Unknown Source)
    at org.opensaml.xml.encryption.Decrypter.parseInputStream(Decrypter.java:832)
    at org.opensaml.xml.encryption.Decrypter.decryptDataToDOM(Decrypter.java:610)
    at org.opensaml.xml.encryption.Decrypter.decryptUsingResolvedEncryptedKey(Decrypter.java:795)
    at org.opensaml.xml.encryption.Decrypter.decryptDataToDOM(Decrypter.java:535)
    at org.opensaml.xml.encryption.Decrypter.decryptDataToList(Decrypter.java:453)
    at org.opensaml.xml.encryption.Decrypter.decryptData(Decrypter.java:414)
    at org.opensaml.saml2.encryption.Decrypter.decryptData(Decrypter.java:141)
    at org.opensaml.saml2.encryption.Decrypter.decrypt(Decrypter.java:69)
    at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:199)
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:82)
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
    at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
    at sun.reflect.GeneratedMethodAccessor1209.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:277)
    at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:274)
    at java.security.AccessController.doPrivileged(Native Method)
    at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
    at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:309)
    at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:249)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
    at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:55)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:191)
    at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:187)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:186)
    at blackboard.platform.servlet.DevNonceFilter.doFilter(DevNonceFilter.java:68)
    [SNIP]

The reason the problem occurs is another B2/Project changed the system property javax.xml.parsers.DocumentBuilderFactory value from org.apache.xerces.jaxp.DocumentBuilderFactoryImpl to com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl.

Temporary resolution

Until a fix is released, the temporary resolution options are:

  1. Restart Bb services on each node.
  2. Turn off SAML response encryption on the IdP side. As the whole communication is over SSL, this will not reduce the security of the authentication.

No option to add SAML to Provider Order

When configuring SAML authentication, an institution may notice there is not an option to add a SAML authentication provider in the Provider Order section in Blackboard Learn GUI when navigating to System Admin > Building Blocks: Authentication > Provider Order.

The reason there is not an option to add a SAML authentication provider to the Provider Order is that redirect type providers such as CAS and SAML hand off authentication to the remote authentication source. Those are not listed in the Provider Order as they are considered the authoritative source for authentication and handle their own authentication failures.


Test SAML connection

Beginning with the Q4 2016 release of Blackboard Learn, there is now an option to test the connection for a SAML provider in the Authentication section in the Blackboard Learn GUI. The connection test will check the following items:

  • Parse IdP metadata
  • Connect to IdP
  • Receive SAML response
  • Parse SAML response
  • Remote User ID match
  • Log in to Blackboard Learn

To test the connection for a SAML authentication provider:

  1. Login to Blackboard Learn as an administrator.
  2. Navigate to System Admin > Building Blocks: Authentication > «SAML Provider Name» > Test Connection.
  3. Enter the IdP login credentials if prompted.

The Test Connection feature can be used in lieu of manually enabling SAML debug logging in Blackboard Learn for multiple reasons.

The Identity Provider Entity ID value that is displayed on the Test Connection output page is pulled from the Issuer element in the SAML POST from the IdP to Blackboard Learn after the user has been authenticated:

<Issuer xmlns=»urn:oasis:names:tc:SAML:2.0:assertion»>http://bbpdcsi-adfs1.bbpdcsi.local/a…services/trust</Issuer>

The SAML Attribute values displayed on the Test Connection output page in the SAML Response section are pulled from the Subject and AttributeStatement elements in the SAML POST from the IdP to Blackboard Learn after the user has been authenticated:

<Subject>
    <NameID Format=»urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress»>luke.skywalker</NameID>
    [SNIP]
</Subject>
<AttributeStatement>
    <Attribute Name=»SamAccountName»>
        <AttributeValue>luke.skywalker</AttributeValue>
    </Attribute>
    <Attribute Name=»urn:oid:2.5.4.42″>
        <AttributeValue>Luke</AttributeValue>
    </Attribute>
    <Attribute Name=»urn:oid:2.5.4.4″>
        <AttributeValue>Skywalker</AttributeValue>
    </Attribute>
</AttributeStatement>


Create a SAML authentication provider and IdP for testing

Use the steps below to create an Identity Provider (IdP) using Centrify’s free SSO authentication solution.

That IdP can then be configured as the SAML authentication provider in a Blackboard Learn Service Provider (SP):

Blackboard Learn Service Provider

  1. Login to the Blackboard Learn GUI as an administrator and navigate to System Admin > Authentication.
  2. Select Create Provider > SAML.
  3. Input the following settings:
    • Name > SAML or anything you want.
    • Authentication Provider > Inactive (for now).
    • User Lookup Method > Username
    • Restrict by Hostname > Use this provider for any hostnames
    • Link Text > SAML Centrify Login
  4. Select Save and Configure.
  5. In the Entity ID field, set this to anything you want (but if you change it you must provide the updated Service Provider Metadata to the Identity Provider). Simply copy/paste the ACS URL.
  6. Under Service Provider Metadata, select Generate and save the file to your desktop.
  7. Under Data Source, it is recommended to create a new Data Source for this named CENTRIFY, otherwise use SYSTEM or whatever you choose
  8. Next to Enable JIT Provisioning, check this box so that an account is automatically created when attempting to login via this SAML authentication provider if the user does not exist. If JIT Provisioning is not selected, the user in Blackboard Learn will need to be created manually.
  9. In the Compatible Data Sources list, be sure to select the data sources that this authentication provider should be compatible with.
  10. Select Point Identity Provider for the Identity Provider Type.
  11. Skip the Identity Provider Metadata for now, you will upload the file after it has been created in the Centrify IdP section.
  12. For the Map SAML Attributes section, use NameID for the Remote User ID.
  13. Select Submit.

Centrify Identity Provider

  1. Go to the Centrify website and select Start Now.
  2. Enter your information to sign up and select Start Now.
  3. You will receive a welcome email with your admin credentials. Use them to log in to https://cloud.centrify.com.
  4. Select Skip on the Welcome to Centrify Identify Service window.
  5. In the Apps tab at the top of the page, select the Add Web Apps button.
  6. In the Custom tab, scroll down and select the Add button for SAML. Select Yes.
  7. Select Close at the bottom of the Add Web Apps window.
  8. Go to the Apps tab. In the Application Settings section, select the Upload SP Metadata button and upload the file that was created in Step 6 of the Blackboard Learn SP section.
  9. The Assertion Consumer Service URL should automatically populate after uploading the SP Metadata.
  10. Uncheck Encrypt Assertion. This allows the attributes being released from the IdP and sent to Blackboard Learn to be viewed using the Firefox browser SAML tracer Add-on or Chrome SAML Message Decoder. As the whole communication is over SSL this will not reduce the security of the authentication.
  11. Scroll down and select Download Identity Provider SAML Metadata. Save the file to your desktop.
  12. Select Save and go to the next section.
  13. Enter a name for the Description section. Select Save and go to the next section.
  14. In the User Access section, select Everybody and System Administrator. Select Save.
  15. Do not make any selections in the Policy section.
  16. For the Account Mapping section, confirm that userprincipalname is entered for the Directory Service field name.
  17. For the Advanced section, add the following line to the bottom of the script used to generate a SAML assertion for the application:

    The complete script will be:

    setIssuer(Issuer);
    setSubjectName(UserIdentifier);
    setAudience(‘https://YourLearnServer.blackboard.c…saml/saml/SSO’);
    setRecipient(ServiceUrl);
    setHttpDestination(ServiceUrl);
    setSignatureType(‘Assertion’);
    setNameFormat(’emailaddress’);
    setAttribute(«NameID», LoginUser.Get(«userprincipalname»));

    Which will allow the Centrify IdP to release an AttributeStatement with the User ID in the SAML POST.

    Example:

    <AttributeStatement>
        <Attribute Name=»NameID»
                   NameFormat=»urn:oasis:names:tc:SAML:2.0:attrname-format:basic»
                   >
            <AttributeValue>luke.skywalker@blackboard.com.47</AttributeValue>
        </Attribute>
    </AttributeStatement>

    More on specifying assertion elements in the Centrify SAML script

  18. Select Save.
  19. No changes should need to be made to the remaining sections (App Gateway, Changelog and Workflow).
  20. In the Apps tab, confirm the SAML app was automatically deployed.
  21. In the Users tab, select Add Users, enter the account info for a user, and select Create User.
  22. Log back into the Blackboard Learn GUI as an administrator, navigate to System Admin > Authentication > SAML Authentication Provider Name > SAML Settings > Identity Provider Settings, upload the IdP Metadata file that was saved to your desktop in Step 13 and select Submit.

The Centrify IdP user that was created can now login to Blackboard Learn via SAML by selecting that authentication provider on the login page, and logout of Blackboard Learn using the extra End SSO Session logout button on the End all sessions? page that is displayed after selecting the logout button at the top right of Blackboard Learn.


Change text on End SSO Session logout page

An institution may inquire if it is possible to change the text on the End SSO Session logout page. It is possible to change the text on the End SSO Session logout page by editing the Language Pack:

  1. Open the Language Pack file.
  2. Navigate to auth-provider-saml/src/main/webapp/WEB-INF/bundles/bb-manifest-en_US.properties.
  3. Update the Message Keys:

    saml.single.logout.warning.conent.description // the first line
    saml.single.logout.warning.conent.recommend // second line
    saml.single.logout.warning.endsso.title // third line
    saml.single.logout.warning.endsso.button // the button
    saml.single.logout.warning.backtolearn // the cancel button


Redirect users to the IdP login page

The standard Blackboard Learn login page presents username and password fields for the default Learn Internal authentication provider. When you enable SAML authentication, a small «Sign in using…» link for SAML appears at the bottom of this page, so you may want to redirect users to the IdP’s authentication server automatically when they access the Learn login page.

One option to accomplish this is to navigate to System Admin > Authentication and set the default Learn Internal authentication to Inactive, which means a login page is no longer displayed, and immediately the user is redirected to the SAML login. The problem with that option is that it overrides the default login URL and prevents any non-SAML user to login.

To avoid this issue and provide almost the same result, use a Custom Login Page. Users are redirected to the SAML authentication provider’s IdP login page, but the default login link is also usable.

  1. Ensure the default Learn Internal authentication is active
  2. On the default login page, copy the location of the provider redirect e.g. Sign in using… SAML. Right-click on the link and select Copy Link Location.
  3. Navigate to System Admin > Communities > Brands and Themes > Customize Login Page.
  4. Select Download next to Default Login Page to download the default login JSP file.
  5. Open the JSP file with a text editor. Add the following sample HTML to the login JSP file and replace the URL text with the URL that was copied in Step 2.

    <!DOCTYPE HTML PUBLIC «-//W3C//DTD HTML 4.0 Transitional//EN»>
    <html>
    <head>
    <title>Blackboard Learn — Redirect</title>
    <meta http-equiv=»REFRESH» content=»0;url=https://URL_Goes_Here»></HEAD>
    <BODY style=»font-family: arial,sans-serif;font-size: small; color: grey; padding: 1em; «>
    Redirecting… <a style=»color:grey» href=»https://URL_Goes_Here»>Go to login page</a> if you are not automatically redirected.
    </BODY>
    </HTML>

  6. Navigate to Customize Login Page in Learn once more. Select Use Custom Page and then upload the updated login JSP file.
  7. After making the changes, select Preview on the Customize Login Page to confirm the redirect is working properly.

Users going to the main URL will now be redirected to the login page for the SAML authentication provider. Administrators can still log in using the Learn internal authentication via the default login page: /webapps/login/?action=default_login or/webapps/login/login.jsp).

More on customizing the login page in the Ultra experience

    Introduction

    This document describes an issue where you receive an «HTTP Status 401» error message after a period of inactivity when you use Single Sign-On (SSO).

    Prerequisites

    Requirements

    Cisco recommends that you have knowledge of these topics:

    • SSO
    • Active Directory Federation Service (AD FS)
    • CloudCenter

    Components Used

    This document is not restricted to specific software or hardware versions.

    The information in this document was created from the devices in a specific lab environment. All of the devices used in this document started with a cleared (default) configuration. If your network is live, make sure that you understand the potential impact of any command.

    Problem

    When you use SSO, you can receive a «401» error after a period of inactivity, instead of a prompt to log in again as shown in the image.

    The only way for you to be able to log in again is to close the entire web browser and reopen it.

    Solution

    This is caused by a mismatch in the timeout values between CloudCenter and the SSO server.

    An enhancement allows the ForceAuthn Parameters support, which can allow a mismatch between the two values and CloudCenter to log out gracefully. This enhancement can be tracked here https://bst.cloudapps.cisco.com/bugsearch/bug/CSCvg36752.

    The only workaround is to remove the mismatch. There are three locations where the timeout values need to match. The first two are on the CCM itself.

    1. Navigate to /usr/local/tomcat/webapps/ROOT/WEB-INF/web.xml.
    2. Modify the <session-timeout>time_In_Minutes</session-timeout> to reflect the timeout desired in minutes.
    3. Navigate to /usr/local/tomcat/webapps/ROOT/WEB-INF/mgmt.properties.
    4. Modify the saml.maxAuthenticationAge.seconds=timeout_in_seconds to reflect the timeout desired in seconds. 

    The third is on the SSO server and the location can vary which depends on what type of SSO server is running. The web SSO lifetime value must match the two values configured on CloudCenter.

    Once all three match, when the timeout has occurred, you are dropped back to the log in screen before allowed to view the page.

    Цитата
    МихаилИгоревич пишет:

    Цитата
    ecoins77 пишет:
    Всем доброго дня.
    Подскажите, что за «Доля внесения платы, размер доли в %» в шаблоне ЛС?

    Добрый день!
    Не могу понять, где вы шаблон нашли?

    На сайте ГИС ЖКХ / Регламенты и инструкции / Ресурсоснабжающие организации / Проект шаблона импорта ЛС в версию 8.7.0

    Цитата
    На сайте ГИС ЖКХ / Регламенты и инструкции / Ресурсоснабжающие организации / Проект шаблона импорта ЛС в версию 8.7.0

    Это же только проект, ждем обновления 8.7 или кто то умудрился загрузить этот шаблон?

    Цитата
    ecoins77 пишет:
    Всем доброго дня.
    Подскажите, что за «Доля внесения платы, размер доли в %» в шаблоне ЛС?

    Это если 1 собственник, то ставиться 100%.

    Я лично везде ставлю 100 %, а где разделение счетов то по площади ЛС высчитываю % внесения платы, только не уверена, что это так должно быть.

    Цитата
    ecoins77 пишет:

    Цитата
    МихаилИгоревич пишет:

    Цитата
    ecoins77 пишет:
    Всем доброго дня.
    Подскажите, что за «Доля внесения платы, размер доли в %» в шаблоне ЛС?

    Добрый день!
    Не могу понять, где вы шаблон нашли?

    На сайте ГИС ЖКХ / Регламенты и инструкции / Ресурсоснабжающие организации / Проект шаблона импорта ЛС в версию 8.7.0

    Как и говорят, это «ПРОЕКТ». Он сделан для определения, подготовки и структурирования информации. Потом эту информацию можно будет жик-жик и быстренько загрузить))

    Цитата
    Как и говорят, это «ПРОЕКТ». Он сделан для определения, подготовки и структурирования информации. Потом эту информацию можно будет жик-жик и быстренько загрузить))

    Ну хоть вы повеселили :lol: , как правило новый шаблон без бубна с гармошкой не грузится, я сначала добьюсь нормальной загрузки (методом тыка) а уж потом буду заполнять.

    Московская область! Письмо счастья пришло?

    Цитата
    olynka1403 пишет:
    Московская область! Письмо счастья пришло?

    А вот интересно , предлагаемые вам шаблоны сильно отличаются от шаблонов на ГИС ЖКХ ? можете сказать

    Отправлено спустя 2 минуты 28 секунды:

    Цитата
    ktlty пишет:
    кто уже размещал работы покажите скриншот

    А мы решили дождаться обновления версии и обновления Справочника типовых работ , который обещали изменить в соответствии с 290 постановлением

    Цитата
    olynka1403 пишет:
    Московская область! Письмо счастья пришло?

    Сами шаблоны в студию! Пожалста!

    Цитата
    nsk31129 пишет:
    А мы решили дождаться обновления версии и обновления Справочника типовых работ , который обещали изменить в соответствии с 290 постановлением

    Кто и когда обещал? огласите весь текст обещания, пожалуйста! вчера в тех поддержку только звонила по этому вопросу, ничего подобного не сказали…

    Цитата
    Klever пишет:

    Цитата
    nsk31129 пишет:
    А мы решили дождаться обновления версии и обновления Справочника типовых работ , который обещали изменить в соответствии с 290 постановлением

    Кто и когда обещал? огласите весь текст обещания, пожалуйста! вчера в тех поддержку только звонила по этому вопросу, ничего подобного не сказали…

    Вот письменный ответ от поддержки :
    Обращение №30568 от 22.04.2016 по вопросу Вопрос по законодательству

    Уважаемый пользователь!

    В следующих версиях системы будет выполнено обновление справочника «Работы и услуги организации» в соответствии с Постановлением Правительства РФ от 03.04.2013 N 290 «О минимальном перечне услуг и работ, необходимых для обеспечения надлежащего содержания общего имущества в многоквартирном доме, и порядке их оказания и выполнения».
    Обращаем Ваше внимание, что после выхода каждой новой версии Системы, на портале ГИС ЖКХ публикуется информация о реализованных функциональных возможностях системы в соответствии с номером версии.
    Отслеживать изменения возможно в разделе «Регламенты и инструкции» по ссылке

    http://dom.gosuslugi.ru/#/regulations

    в подразделе «Журнал версий».
    Для сохранения истории взаимодействия при последующей переписке по данному запросу просим Вас сохранять тему письма. При возникновении новых вопросов просьба направлять новое обращение по «Форме заявки в службу поддержки». Благодарим за обращение в службу технической поддержки Портала ГИС ЖКХ!

    С уважением,
    Служба технической поддержки
    ГИС ЖКХ

    Это что такое? Кто подскажет 88q

    Цитата
    Башкирия пишет:
    Это что такое? Кто подскажет 88q

    У всех такое, говорят. что с крипто про связанно, я жму кнопку принять и работаю!

    Кто что делает с номерами приборов учета? ходить по квартирам переписывать не вариант, документов на все счетчики нет, придумывать свои?

    Цитата
    МихаилИгоревич пишет:

    Цитата
    olynka1403 пишет:
    Московская область! Письмо счастья пришло?

    Сами шаблоны в студию! Пожалста!

    Очень хочется на это посмотреть. Пожалуйста прикрепите если возможно. Нам это счастье еще не прислали. Зато срочно требуют заполнить АИС ГЖИ Дома Подмосковья .

    По лицевым счетам думаю нет причин торопиться — там отсутствует один показатель, который будет дополнен и который очень сильно повлияет на трудоёмкость. Я пока просто готовлю первичку.
    По «Работы и услуги организации» — спорно. Для реализации 290 там существует другой справочник связанный с указанным вами. Представить себе перечень на 300+ строк для утверждения собственниками получается с трудом.

    Цитата
    Егор пишет:
    По лицевым счетам думаю нет причин торопиться — там отсутствует один показатель, который будет дополнен и который очень сильно повлияет на трудоёмкость. Я пока просто готовлю первичку.
    По «Работы и услуги организации» — спорно. Для реализации 290 там существует другой справочник связанный с указанным вами. Представить себе перечень на 300+ строк для утверждения собственниками получается с трудом.

    По поводу подготовки к внесению перечня работ и услуг , Типовой справочник ГИС ограничен , работ не хватает ,а вносить новые — нельзя , как быть ? Нужно же составить соответствие работ один в один со своей инф.системой , может быть новая версия и новый справочник поможет решить эту задачу

    Справочников будет 3.
    1. Обязательные работы — по законодательству. (править нельзя)
    2. Типовые работы (связан с 1). (править нельзя)
    3. Пользовательские работы (связан с 1) — любые работы сделанные как на основании типовых так и полностью с нуля правятся организацией.

    Отправлено спустя 45 секунды:

    Цитата
    olynka1403 пишет:
    Московская область! Письмо счастья пришло?

    Очень хочу получить приложения к этому письму. Срочно. У кого есть пришли пожалуйста.

    Цитата
    Серега жкх пишет:
    Добрый всем день!
    Помогите, пожалуйста, при входе в систему на организацию появляется
    Request failed

    The request failed. The reason is:

    Unable to validate SAML message!

    Stacktrace:
    Что это такое и что нужно делать. В прошлом году регистрировался, заходил, все было нормально.

    Кто-нибудь поможет или ни у кого такого не было?

    Цитата
    Егор пишет:
    По лицевым счетам думаю нет причин торопиться — там отсутствует один показатель, который будет дополнен и который очень сильно повлияет на трудоёмкость.

    Что это за показатель такой если не секрет?
    Только решусь что нибудь заполнить, а там все сыро…

    Вот шаблоны которые мне прислали… Такое ощущение что все они из разных версий ГИС ЖКХ…

    Цитата
    platinum09 пишет:

    Цитата
    Егор пишет:
    По лицевым счетам думаю нет причин торопиться — там отсутствует один показатель, который будет дополнен и который очень сильно повлияет на трудоёмкость.

    Что это за показатель такой если не секрет?
    Только решусь что нибудь заполнить, а там все сыро…

    Кадастровый номер помещения

    Цитата
    Егор пишет:
    Кадастровый номер помещения

    Да ладно…. Он че обязательный будет??? Заняться больше нечем росреестр перерывать
    Фу на этот ГИС

    Не зайти в Гис, только грузит, у Вас также? снова видать какие то разработки.

    Цитата
    nika пишет:
    Не зайти в Гис, только грузит, у Вас также? снова видать какие то разработки.

    и вчера так же было, каждое утро как наркоман несусь смотреть на обновление системы и облом :lol:

    издеваются. Как можно заставлять вносить данные, если проект не доработан и постоянно глючит?

    А может кто-нибудь сказать, что должно быть точно внесено до 1.07.2016г?!

    обычный пользователь видит только дома и квартиры.

    Troubleshooting

    When you face an issue you could try to enable a logger to these two packages on the level specified and try to find errors, this will show in logs the information send from Jenkins (SP) to the SAML service (IdP), this information could be sensitive so take care where you copy/send it.

    * org.jenkinsci.plugins.saml - FINEST
    * org.pac4j - FINE
    

    If you have configured the Jenkins proxy setting, and you do not want to use the proxy to connect to your IdP you have to add your IdP to no-proxy hosts

    IdP Metadata

    The IdP metadata should look like this one, the main data are the entityID, IDPSSODescriptor section, and SingleSignOnService the three sections are needed.

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <EntityDescriptor xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
        xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
        entityID="https://SAML_SERVER/idp/">
        <!-- The SSO service at the identity provider -->
        <IDPSSODescriptor WantAuthnRequestsSigned="false"
            protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
            <KeyDescriptor use="signing">
                <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                    <ds:X509Data>
                        <ds:X509Certificate>sEqZ5xC8GFgcPcUOI6CnUYDnO630cAqHjLdVp82eaxFRr7F8j75Go7b/HiWcp87iOAzQ8NrCWUwYzny7mogvopNq2/oONqNXML4pM6v8epHWAZePBcW+o5tVJMYseAl7bwX/VE3Ro8LakHoBbDlRaiHT3A55p4Vyp0OZUGHLazrV9yCKvvDPU+pPocB4PKR3nBOQ9AyF0r1a8T8/y90X59BpHJxhXfJSgT8U/95KIV9+cEb11BApr5a3KrxIZAep6CC4C9MVmIsUSjpM6bOt4qqiQC9WVbD5i5ZnimiFYvHt/QOvyFT751T9QylWz2SGwzyqwG6+LZXswbeITjcrSZkdInkkWybqC+igvOrSOi6sSn5GjSHQqskCI6GwYNQ9ndAsWBwRdyx+ydZGVo0riZurc/YdhH13VpLnx6Vrk8+Sbf0oHqr7BSdSnl1bi/qptIg9ksF5Zw8Rkep9118A88w7uEEBO3q+fGfE72FYMxsp5k/MSLgKkwqlCpqzhmCd2L6ZU/g45sEQSwdaS9YzsY7o4kGrzSzCGxsinP/67UddiTFiJNan2zzVyeVUdKthbek5hHNord9durQXN8O4t5wlMFS+67+ReCs1g/S+eKJelvH5aPtbPE7lttt/hZ8LgKX2vGT5yFcQmT46Kj6u3tSbNGnipl4BQ1ItbQZoe1g=
                        </ds:X509Certificate>
                    </ds:X509Data>
                </ds:KeyInfo>
            </KeyDescriptor>
            <!-- Supported Name Identifier Formats -->
            <NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</NameIDFormat>
            <!-- AuthenticationRequest Consumer endpoint -->
            <SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://SAML_SERVER/idp"/>
            <SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://SAML_SERVER/idp"/>
        </IDPSSODescriptor>
    </EntityDescriptor>
    

    SAMLResponse

    This is an example of SAMLResponse, it is the message sent by the IdP to Jenkins, it should contain an Assertion with signature details if it is supported by the IdP, a Subject with the request details, Conditions with the validity of the session, AuthnStatement with the session details, finally a AttributeStatement with the attributes sent by the IdP.

    <Response
        xmlns="urn:oasis:names:tc:SAML:2.0:protocol"
        Destination="https://JENKINS_SERVER/securityRealm/finishLogin"
        ID="_c266abbff66bba8bcd763443655ea1c5861d"
        InResponseTo="_75a5cb8c9514c22751e05b29e698e0e8"
        IssueInstant="2016-04-18T19:04:53Z"
        Version="2.0">
        <ns1:Issuer xmlns:ns1="urn:oasis:names:tc:SAML:2.0:assertion"
            Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://SAML_SERVER/idp/</ns1:Issuer>
        <Status>
            <StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
        </Status>
        <ns2:Assertion xmlns:ns2="urn:oasis:names:tc:SAML:2.0:assertion" ID="_4d406d6505202232c48a50726c55d58f548c"            
            IssueInstant="2016-04-18T19:04:53Z" Version="2.0">
            <ns2:Issuer Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">https://SAML_SERVER/idp/</ns2:Issuer>
            <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <ds:SignedInfo>
                    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
                    <ds:Reference URI="#_4d406d6505202232c48a50726c55d58f548c">
                        <ds:Transforms>
                            <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
                            <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                        </ds:Transforms>
                        <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
                        <ds:DigestValue>B+nZTeDSNSpigeyDg2475274242ARIw6ttEXHY3PMk=</ds:DigestValue>
                    </ds:Reference>
                </ds:SignedInfo>
                <ds:SignatureValue>VTCuyYj09/CbuU7+pX6g3wjTlocTH83RkWEG6xy2t1ZSDPS0Q0gjfmh8/HMNSOoold9i2zY5Qi4/idZ7yKBe0nR7WDZDPkc3FSovvX73FThJEZ5aJk/6uhr5yUzj3qypA9bLsHdMO75SfaDzotb0c4mIBWLuPX245sZretx6pNRHDYntgQB9ikYC6UQPuSwn1+p/iq1B+GnbNp7m+og0rL5ooc7jPnpqiWBn2648ZCSsnoemrCiSmDVR90XJ7GFEz27W7BH8ZH49DdML6xmqiBvWmZC7LpfkcoF54mLZMdVYM=
                </ds:SignatureValue>
                <ds:KeyInfo>
                    <ds:X509Data>
                        <ds:X509Certificate>gpEQ4+mCQGMhwPtrqp1fPXpocgNZ9NkH/FZ62bzYTswVBF6VJPm5VuslmxGTVOMBd/qNKin/xlX2nL5J4mABXZ3OrUcyX//cwK3zqyS2Gn9LaAQnwOdkpXVQzeufCS0agrpfOtEKwWHgbs1m4Dfcl82SWOSbBZhLOUmtDMa0y1DqMB2nxVwJY8ULD+p3HUJGnGxx7JvGBo3OM/tZ3DC7zC0QGlPfuMFPT1GuKsdG11OZ1kWNa9XxQj8pOpPDuiBrxCJDz5vM00ThgnkORITYSkWPO05oe+RBms/qcfYH5JOiR5NJMxojAv2jqvAT8YES1l376yaHWEampzH1nWdW9XQvpr9l297yK7GxGU3Pj4M7ryalYXyH/5tqGFkcQQsX6TDUcmy4M6DlRTe3f7U3duEA1KlQApShDU7lYt41g8vv7pVFN14z9ZNhztJIErmkvR0H/QHR2SVg+WWM0Ql+rMzgsYVfPa4xCIpfEmiWujeeboJay+492k3Im5XbUUCG49UHigyoaAbLIwrCpnFLd3bGlAjun75WWbAHlaILkXAhTNMSPpbWBXrfhwgLwYK5zLGgkpsQPKzzAvQoLHT0wP0R1CbHWGmyNE45ArY3QK0BFb0IRxysNjYIu276JkDjxpdK93ofnWImwE9NLxWh/rqJ2IJ/+6dl8tnYVoT1adg=
                        </ds:X509Certificate>
                    </ds:X509Data>
                </ds:KeyInfo>
            </ds:Signature>
            <!-- User information -->
            <ns2:Subject>
                <ns2:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">USER_NAME</ns2:NameID>
                <ns2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
                <ns2:SubjectConfirmationData InResponseTo="_75a5cb8c9514c22751e05b29e698e0e8" NotOnOrAfter="2016-04-18T19:06:23Z"   
                    Recipient="https://JENKINS_SERVER/securityRealm/finishLogin"/>
                </ns2:SubjectConfirmation>
            </ns2:Subject>
            <!-- expiration of session -->
            <ns2:Conditions NotBefore="2016-04-18T19:04:23Z" NotOnOrAfter="2016-04-18T19:06:23Z">
                <ns2:AudienceRestriction>
                    <ns2:Audience>https://JENKINS_SERVER/securityRealm/finishLogin</ns2:Audience>
                </ns2:AudienceRestriction>
            </ns2:Conditions>
            <ns2:AuthnStatement AuthnInstant="2016-04-18T19:04:53Z" SessionIndex="/47O5ynZIyr+2365762LqnEmAZs=JI+mPg=="
                SessionNotOnOrAfter="2016-04-18T19:06:23Z">
                <ns2:AuthnContext>
                    <ns2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</ns2:AuthnContextClassRef>
                    </ns2:AuthnContext>
            </ns2:AuthnStatement>
            <!-- Authorization Groups -->
            <ns2:AttributeStatement>
                <ns2:Attribute name="groups">
                    <ns2:AttributeValue>groupOne</ns2:AttributeValue>
                    <ns2:AttributeValue>groupTwo</ns2:AttributeValue>
                    <ns2:AttributeValue>groupThree</ns2:AttributeValue>                       
                </ns2:Attribute>
            </ns2:AttributeStatement>
        </ns2:Assertion>
    </Response>
    

    SAMLException: Identity provider has no single sign on service available for the selected

    You have to check your IdP metadata contains the section SingleSignOnService

    org.pac4j.saml.exceptions.SAMLException: Identity provider has no single sign on service available for the selected profileorg.opensaml.saml.saml2.metadata.impl.IDPSSODescriptorImpl@628767f5
    	at org.pac4j.saml.context.SAML2MessageContext.getIDPSingleSignOnService(SAML2MessageContext.java:93)
    

    Azure AD

    After leaving the system for some period of time (like overnight) and trying to log in again you get this error

    org.pac4j.saml.exceptions.SAMLException: No valid subject assertion found in response 
    at org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator.validateSamlSSOResponse(SAML2DefaultResponseValidator.java:313) 
    at org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator.validate(SAML2DefaultResponseValidator.java:138) 
    at org.pac4j.saml.sso.impl.SAML2WebSSOMessageReceiver.receiveMessage(SAML2WebSSOMessageReceiver.java:77) 
    at org.pac4j.saml.sso.impl.SAML2WebSSOProfileHandler.receive(SAML2WebSSOProfileHandler.java:35) 
    at org.pac4j.saml.client.SAML2Client.retrieveCredentials(SAML2Client.java:225) 
    at org.pac4j.saml.client.SAML2Client.retrieveCredentials(SAML2Client.java:60) 
    at org.pac4j.core.client.IndirectClient.getCredentials(IndirectClient.java:106) 
    at org.jenkinsci.plugins.saml.SamlProfileWrapper.process(SamlProfileWrapper.java:53) 
    at org.jenkinsci.plugins.saml.SamlProfileWrapper.process(SamlProfileWrapper.java:33) 
    at org.jenkinsci.plugins.saml.OpenSAMLWrapper.get(OpenSAMLWrapper.java:65) 
    at org.jenkinsci.plugins.saml.SamlSecurityRealm.doFinishLogin(SamlSecurityRealm.java:265) 
    at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:627) 
    at org.kohsuke.stapler.Function$MethodFunction.invoke(Function.java:343) 
    at org.kohsuke.stapler.Function.bindAndInvoke(Function.java:184) 
    at org.kohsuke.stapler.Function.bindAndInvokeAndServeResponse(Function.java:117) 
    at org.kohsuke.stapler.MetaClass$1.doDispatch(MetaClass.java:129) 
    at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:58) 
    at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:715) 
    Caused: javax.servlet.ServletException at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:765) 
    
    ...
    at winstone.BoundedExecutorService$1.run(BoundedExecutorService.java:77) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) 
    at java.lang.Thread.run(Thread.java:748)
    
    • Click on logout button, then hit the Jenkins sign-in again.
    • Clear the cookies in your browser or Go to Azure and sign out of the username, then hit the Jenkins sign-in again.
    • The max lifetime of the Access Token in Azure AD seems to be 24 hours when the refresh token can live for a maximum of 14 days (if the access token expires the refresh token is used to try to obtain a new access token). The Jenkins setting in Configure Global Security > SAML Identity Provider Settings > Maximum Authentication Lifetime is 24 hours (86400 in seconds) upping this to 1209600 (which is 14 days in seconds/the max lifetime of the Refresh Token).
    • Enable the advanced «force authentication» setting is another workaround.

    Identity provider has no single sign on service available for the selected…

    • Check the SP EntryID configured on the IdP
    • Check the binding methods supported on your IdP
    org.pac4j.saml.exceptions.SAMLException: Identity provider has no single sign on service available for the selected profileorg.opensaml.saml.saml2.metadata.impl.IDPSSODescriptorImpl@7ef38e46
    	at org.pac4j.saml.context.SAML2MessageContext.getIDPSingleSignOnService(SAML2MessageContext.java:93)
    	at org.pac4j.saml.sso.impl.SAML2AuthnRequestBuilder.build(SAML2AuthnRequestBuilder.java:70)
    	at org.pac4j.saml.sso.impl.SAML2AuthnRequestBuilder.build(SAML2AuthnRequestBuilder.java:34)
    	at org.pac4j.saml.client.SAML2Client.retrieveRedirectAction(SAML2Client.java:209)
    	at org.pac4j.core.client.IndirectClient.getRedirectAction(IndirectClient.java:79)
    	at org.jenkinsci.plugins.saml.SamlRedirectActionWrapper.process(SamlRedirectActionWrapper.java:47)
    	at org.jenkinsci.plugins.saml.SamlRedirectActionWrapper.process(SamlRedirectActionWrapper.java:30)
    	at org.jenkinsci.plugins.saml.OpenSAMLWrapper.get(OpenSAMLWrapper.java:65)
    	at org.jenkinsci.plugins.saml.SamlSecurityRealm.doCommenceLogin(SamlSecurityRealm.java:260)
    	at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:627)
    	at org.kohsuke.stapler.Function$MethodFunction.invoke(Function.java:343)
    	at org.kohsuke.stapler.Function.bindAndInvoke(Function.java:184)
    	at org.kohsuke.stapler.Function.bindAndInvokeAndServeResponse(Function.java:117)
    	at org.kohsuke.stapler.MetaClass$1.doDispatch(MetaClass.java:129)
    	at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:58)
    	at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:715)
    

    Identity provider does not support encryption settings

    • Check the encryption methods, signing methods, and keys types supported by your IdP and set the encryption settings correctly
    • Downgrade to 0.14 version, if it works, then enable encryption on that version to be sure that this is the issue
    • Check the JDK version does not have issues like this JDK-8176043
    2017-10-18 20:26:49.568+0000 [id=1296]	WARNING	o.j.p.s.SuppressionFilter#reportError: Request processing failed. URI=/securityRealm/finishLogin clientIP=192.168.1.100 ErrorID=b04ec3d5-8fbe-4961-88f2-187f47649000
    org.opensaml.messaging.decoder.MessageDecodingException: This message decoder only supports the HTTP POST method
    	at org.pac4j.saml.transport.Pac4jHTTPPostDecoder.doDecode(Pac4jHTTPPostDecoder.java:57)
    	at org.opensaml.messaging.decoder.AbstractMessageDecoder.decode(AbstractMessageDecoder.java:58)
    	at org.pac4j.saml.sso.impl.SAML2WebSSOMessageReceiver.receiveMessage(SAML2WebSSOMessageReceiver.java:40)
    Caused: org.pac4j.saml.exceptions.SAMLException: Error decoding saml message
    	at org.pac4j.saml.sso.impl.SAML2WebSSOMessageReceiver.receiveMessage(SAML2WebSSOMessageReceiver.java:43)
    	at org.pac4j.saml.sso.impl.SAML2WebSSOProfileHandler.receive(SAML2WebSSOProfileHandler.java:35)
    	at org.pac4j.saml.client.SAML2Client.retrieveCredentials(SAML2Client.java:225)
    	at org.pac4j.saml.client.SAML2Client.retrieveCredentials(SAML2Client.java:60)
    	at org.pac4j.core.client.IndirectClient.getCredentials(IndirectClient.java:106)
    	at org.jenkinsci.plugins.saml.SamlProfileWrapper.process(SamlProfileWrapper.java:53)
    
    Caused by: java.lang.IllegalArgumentException: Illegal base64 character d
        at java.util.Base64$Decoder.decode0(Base64.java:714)
        at java.util.Base64$Decoder.decode(Base64.java:526)
        at java.util.Base64$Decoder.decode(Base64.java:549)
        at org.jenkinsci.plugins.saml.SamlSecurityRealm.doFinishLogin(SamlSecurityRealm.java:258)
    

    The SAMLResponse is not correct base64 encode

    The SAMLResponse message is not valid because the SAMLResponse value is not in Base64 format, or it is corrupted.

    Caused by: java.lang.IllegalStateException: org.pac4j.saml.exceptions.SAMLException: Error decoding saml message
    	at org.jenkinsci.plugins.saml.SamlProfileWrapper.process(SamlProfileWrapper.java:68)
    	at org.jenkinsci.plugins.saml.SamlProfileWrapper.process(SamlProfileWrapper.java:39)
    	at org.jenkinsci.plugins.saml.OpenSAMLWrapper.get(OpenSAMLWrapper.java:65)
    	at org.jenkinsci.plugins.saml.SamlSecurityRealm.doFinishLogin(SamlSecurityRealm.java:272)
    	at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:627)
    	at org.kohsuke.stapler.Function$MethodFunction.invoke(Function.java:343)
    	... 77 more
    

    There is no SAMLResponse parameter in the POST message

    The response message should have a parameter named SAMLResponse that should be the XML of the SAMLResponse in Base64 format.

    Caused by: org.opensaml.messaging.decoder.MessageDecodingException: Request did not contain either a SAMLRequest or SAMLResponse parameter. Invalid request for SAML 2 HTTP POST binding.
    	at org.pac4j.saml.transport.Pac4jHTTPPostDecoder.getBase64DecodedMessage(Pac4jHTTPPostDecoder.java:80)
    	at org.pac4j.saml.transport.Pac4jHTTPPostDecoder.doDecode(Pac4jHTTPPostDecoder.java:62)
    	at org.opensaml.messaging.decoder.AbstractMessageDecoder.decode(AbstractMessageDecoder.java:58)
    	at org.pac4j.saml.sso.impl.SAML2WebSSOMessageReceiver.receiveMessage(SAML2WebSSOMessageReceiver.java:40)
    	... 87 more
    

    No valid subject assertion found in response

    Check that the SP Entry ID it is the same in the SP (Jenkins) and IdP, by default Jenkins uses JENKINS_URL/securityRealm/finishLogin you can change this value if you use the SAML Plugin’s Advanced Setting named «SP Entity ID».

    org.pac4j.saml.exceptions.SAMLException: No valid subject assertion found in response 
    at org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator.validateSamlSSOResponse(SAML2DefaultResponseValidator.java:313) 
    at org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator.validate(SAML2DefaultResponseValidator.java:138) 
    at org.pac4j.saml.sso.impl.SAML2WebSSOMessageReceiver.receiveMessage(SAML2WebSSOMessageReceiver.java:77) 
    at org.pac4j.saml.sso.impl.SAML2WebSSOProfileHandler.receive(SAML2WebSSOProfileHandler.java:35) 
    at org.pac4j.saml.client.SAML2Client.retrieveCredentials(SAML2Client.java:225) 
    at org.pac4j.saml.client.SAML2Client.retrieveCredentials(SAML2Client.java:60) 
    at org.pac4j.core.client.IndirectClient.getCredentials(IndirectClient.java:106) 
    at org.jenkinsci.plugins.saml.SamlProfileWrapper.process(SamlProfileWrapper.java:53) 
    at org.jenkinsci.plugins.saml.SamlProfileWrapper.process(SamlProfileWrapper.java:33) 
    at org.jenkinsci.plugins.saml.OpenSAMLWrapper.get(OpenSAMLWrapper.java:65) 
    at org.jenkinsci.plugins.saml.SamlSecurityRealm.doFinishLogin(SamlSecurityRealm.java:265) 
    at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:627) 
    at org.kohsuke.stapler.Function$MethodFunction.invoke(Function.java:343) 
    at org.kohsuke.stapler.Function.bindAndInvoke(Function.java:184) 
    at org.kohsuke.stapler.Function.bindAndInvokeAndServeResponse(Function.java:117) 
    at org.kohsuke.stapler.MetaClass$1.doDispatch(MetaClass.java:129) 
    at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:58) 
    at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:715) 
    Caused: javax.servlet.ServletException at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:765) 
    
    ...
    at winstone.BoundedExecutorService$1.run(BoundedExecutorService.java:77) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) 
    at java.lang.Thread.run(Thread.java:748)
    

    Authentication issue instant is too old or in the future

    You should check that your Maximum Authentication Lifetime setting is the same that your Idp has, if Jenkins has a lower value you will see this error. The solution is to set Maximum Authentication Lifetime to your token validity. Another workaround is to set Advanced Configuration/Force Authentication but this will ask for login everytime the session expires.

    Oct 26, 2018 9:08:44 PM org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator validateSamlSSOResponse
    SEVERE: Current assertion validation failed, continue with the next oneorg.pac4j.saml.exceptions.SAMLException: Authentication issue instant is too old or in the future
      at org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator.validateAuthenticationStatements(SAML2DefaultResponseValidator.java:620)
      at org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator.validateAssertion(SAML2DefaultResponseValidator.java:393)
      at org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator.validateSamlSSOResponse(SAML2DefaultResponseValidator.java:302)
      at org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator.validate(SAML2DefaultResponseValidator.java:138)
      at org.pac4j.saml.sso.impl.SAML2WebSSOMessageReceiver.receiveMessage(SAML2WebSSOMessageReceiver.java:77)
      at org.pac4j.saml.sso.impl.SAML2WebSSOProfileHandler.receive(SAML2WebSSOProfileHandler.java:35)
      at org.pac4j.saml.client.SAML2Client.retrieveCredentials(SAML2Client.java:225)
      at org.pac4j.saml.client.SAML2Client.retrieveCredentials(SAML2Client.java:60)
      at org.pac4j.core.client.IndirectClient.getCredentials(IndirectClient.java:106)
      at org.jenkinsci.plugins.saml.SamlProfileWrapper.process(SamlProfileWrapper.java:55)
      at org.jenkinsci.plugins.saml.SamlProfileWrapper.process(SamlProfileWrapper.java:35)
      at org.jenkinsci.plugins.saml.OpenSAMLWrapper.get(OpenSAMLWrapper.java:64)
      at org.jenkinsci.plugins.saml.SamlSecurityRealm.doFinishLogin(SamlSecurityRealm.java:304)
    ....
      at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:352)
      at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260)
      at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:281)
      at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102)
      at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118)
      at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333)
      at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:310)
      at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168)
      at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:126)
      at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:366)
      at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:762)
      at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:680)
      at java.lang.Thread.run(Thread.java:748)
    

    Unable to create/read keystore

    The key store is needed by the pac4j library even do you do not use encryption,
    because of that the plugin manages a dummy keystore, it is created and the key is maintained in case it expired.
    It should be transparent for the user, we saw some cases that cannot write the JENKINS_HOME/saml-jenkins-keystore.jks
    and also fails to read the keystore inside the jar.

    WARNING: Using bundled keystore : /srv/jenkins/home/saml-jenkins-keystore.jks (Permission denied)
    Jun 19, 2019 8:19:44 AM org.jenkinsci.plugins.saml.OpenSAMLWrapper createSAML2Client
    WARNING: Using bundled keystore : resource:samlKeystore.jks
    
    Stack trace
    org.pac4j.core.exception.TechnicalException: Unsupported resource format: jar:file:/srv/jenkins/home/plugins/saml/WEB-INF/lib/saml.jar!/samlKeystore.jks. Use a relative or absolute path
    	at org.pac4j.core.util.CommonHelper$1.getFilename(CommonHelper.java:373)
    	at org.pac4j.saml.client.SAML2ClientConfiguration.getKeystorePath(SAML2ClientConfiguration.java:313)
    	at org.pac4j.saml.crypto.KeyStoreCredentialProvider.<init>(KeyStoreCredentialProvider.java:92)
    	at org.pac4j.saml.client.SAML2Client.initCredentialProvider(SAML2Client.java:174)
    	at org.pac4j.saml.client.SAML2Client.internalInit(SAML2Client.java:111)
    	at org.pac4j.core.util.InitializableWebObject.init(InitializableWebObject.java:24)
    	at org.jenkinsci.plugins.saml.OpenSAMLWrapper.createSAML2Client(OpenSAMLWrapper.java:145)
    	at org.jenkinsci.plugins.saml.SamlRedirectActionWrapper.process(SamlRedirectActionWrapper.java:45)
    	at org.jenkinsci.plugins.saml.SamlRedirectActionWrapper.process(SamlRedirectActionWrapper.java:30)
    	at org.jenkinsci.plugins.saml.OpenSAMLWrapper.get(OpenSAMLWrapper.java:64)
    	at org.jenkinsci.plugins.saml.SamlSecurityRealm.doCommenceLogin(SamlSecurityRealm.java:258)
    	at java.lang.invoke.MethodHandle.invokeWithArguments(MethodHandle.java:627)
    	at org.kohsuke.stapler.Function$MethodFunction.invoke(Function.java:396)
    	at org.kohsuke.stapler.Function$InstanceFunction.invoke(Function.java:408)
    	at org.kohsuke.stapler.Function.bindAndInvoke(Function.java:212)
    	at org.kohsuke.stapler.Function.bindAndInvokeAndServeResponse(Function.java:145)
    	at org.kohsuke.stapler.MetaClass$11.doDispatch(MetaClass.java:537)
    	at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:58)
    	at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:739)
    

    The solution is to allow to create the $JENKINS_HOME/saml-jenkins-keystore.jks, remove the existing files and ensure
    Jenkins can create those files.

    rm $JENKINS_HOME/saml-jenkins-keystore.jks
    rm $JENKINS_HOME/saml-jenkins-keystore.xml
    

    Intended destination ${URL} doesn’t match any of the endpoint URLs on endpoint

    2019-11-27 16:55:46.826+0000 [id=4549]	WARNING	o.j.p.saml.SamlSecurityRealm#doFinishLogin: Unable to validate the SAML Response: org.pac4j.saml.exceptions.SAMLException: Intended destination https://JENKINS_SERVER/securityRealm/finishLogin doesn't match any of the endpoint URLs on endpoint http://JENKINS_SERVER/securityRealm/finishLogin; nested exception is org.pac4j.saml.exceptions.SAMLException: org.pac4j.saml.exceptions.SAMLException: Intended destination https://JENKINS_SERVER/securityRealm/finishLogin doesn't match any of the endpoint URLs on endpoint http://JENKINS_SERVER/securityRealm/finishLogin
    For more info check 'Maximum Authentication Lifetime' at https://github.com/jenkinsci/saml-plugin/blob/master/doc/CONFIGURE.md#configuring-plugin-settings
    If you have issues check the troubleshoting guide at https://github.com/jenkinsci/saml-plugin/blob/master/doc/TROUBLESHOOTING.md
    org.pac4j.saml.exceptions.SAMLException: Intended destination https://JENKINS_SERVER/securityRealm/finishLogin doesn't match any of the endpoint URLs on endpoint http://JENKINS_SERVER/securityRealm/finishLogin
    	at org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator.verifyEndpoint(SAML2DefaultResponseValidator.java:280)
    Caused: org.pac4j.saml.exceptions.SAMLException
    	at org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator.verifyEndpoint(SAML2DefaultResponseValidator.java:283)
    	at org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator.validateSamlProtocolResponse(SAML2DefaultResponseValidator.java:234)
    	at org.pac4j.saml.sso.impl.SAML2DefaultResponseValidator.validate(SAML2DefaultResponseValidator.java:132)
    	at org.pac4j.saml.sso.impl.SAML2WebSSOMessageReceiver.receiveMessage(SAML2WebSSOMessageReceiver.java:77)
    	at org.pac4j.saml.sso.impl.SAML2WebSSOProfileHandler.receive(SAML2WebSSOProfileHandler.java:35)
    	at org.pac4j.saml.client.SAML2Client.retrieveCredentials(SAML2Client.java:225)
    	at org.pac4j.saml.client.SAML2Client.retrieveCredentials(SAML2Client.java:60)
    	at org.pac4j.core.client.IndirectClient.getCredentials(IndirectClient.java:106)
    	at org.jenkinsci.plugins.saml.SamlProfileWrapper.process(SamlProfileWrapper.java:55)
    Caused: org.acegisecurity.BadCredentialsException: org.pac4j.saml.exceptions.SAMLException: Intended destination https://JENKINS_SERVER/securityRealm/finishLogin doesn't match any of the endpoint URLs on endpoint http://JENKINS_SERVER/securityRealm/finishLogin; nested exception is org.pac4j.saml.exceptions.SAMLException: org.pac4j.saml.exceptions.SAMLException: Intended destination https://JENKINS_SERVER/securityRealm/finishLogin doesn't match any of the endpoint URLs on endpoint http://JENKINS_SERVER/securityRealm/finishLogin
    	at org.jenkinsci.plugins.saml.SamlProfileWrapper.process(SamlProfileWrapper.java:59)
    	at org.jenkinsci.plugins.saml.SamlProfileWrapper.process(SamlProfileWrapper.java:35)
    	at org.jenkinsci.plugins.saml.OpenSAMLWrapper.get(OpenSAMLWrapper.java:64)
    	at org.jenkinsci.plugins.saml.SamlSecurityRealm.doFinishLogin(SamlSecurityRealm.java:311)
    

    This specific exception if read carefully shows that the intended destination has https protocol but the endpoint URL is using http but otherwise they are equal.

    • Check that HTTPS is enabled on Jenkins or Reverse Proxy
    • Make sure that «Jenkins Location» in System Configuration is set to the https URL

    It is not possible to disable signature with HTTP redirect binding

    Disabling signing setting does not work with redirect binding,
    It happens since we update the pac4j library on 1.0.2.
    In 1.9.9 pac4j library forceSignRedirectBindingAuthnRequest
    and authnRequestSigned do not work as expected.
    Indeed it is not possible to change the value of authnRequestSigned,
    We’ve to extend the class to overwrite the isAuthnRequestSigned() method
    and add a setAuthnRequestSigned() method,
    but this workaround only works with POST binding.
    It is not possible to upgrade the library again because it uses a newer version of Sprint
    and Jenkins Core uses an old one.
    So the only solution is to stop using pac4j library,
    and use OpenSAML library directly, but this is a reimplementation of the plugin.

    After an update the authentication fails

    The first thing to check after and update in case of error it is if the Service provider metadata has changed,
    this metadata is available at the URL JENKINS_URL/securityRealm/metadata, or in the file JENKINS_HOME/saml-sp-metadata.xml
    If you IdP support to grab the metadata from an URL is recommended to use the metadata from the URL JENKINS_URL/securityRealm/metadata

    After login a HTTP ERROR 403 No valid crumb was included in the request error happens

    This is a configuration error, SAML plugin cannot return a ‘invalid breadcrumb’ error in a login process
    if the SP and IdP are correctly configured.
    It happens because the redirection to https://jenkins.example.com/securityRealm/finishLogin is redirected to another URL in Jenkins.
    The error usually is related to the Jenkins URL configured, or a reverse proxy configured in front Jenkins that require a valid crumb.
    Put the log in verbose mode and check the login process, check that the URLs you are redirected are correct.
    SeeTroubleshooting Guide
    and Configure your IdP

    Bill,

    The Issuance Transform Rules simply tell AD FS which attributes to release upon successful authentication.

    If you want to limit who AD FS sends out the attributes to, you will want to set up an Issuance Authorization Rule instead.  Strangely in your screenshot I don’t see the ‘Issuance Authorization Rules’ tab at the top of the window.  What version of AD FS are you using (or what version of Windows is AD FS on)?

    If you click on the Relying Party Trust for your AGOL Org and click ‘Edit Claim Rules…» on the right, you should get a window like the screenshot below.  In the Issuance Authorization Rules tab, you will want to remove the default rule («Permit Access to All Users») and add one under the «Permit or Deny Users Based on an Incoming Claim» template:

    Select «Group SID» under Incoming claim type, then click Browse and enter the names of the groups you want to allow access:

    I hope this information is helpful!

    -Danny

    i’m trying Okta quick start for Java tomcat SAML, I am very new to this topic.
    When I start my test application I do see a link to Okta IDP, after clicking «Start single sign-on» button i am being redirected to Okta address with info «Sining in to SAML — Test» (my Okta test name) after that I’m again being redirected to my application with:

    Error
    Error validating SAML message

    after that there is a stack trace with

    Caused by: org.opensaml.common.SAMLException: Response doesn't have any valid assertion which would pass subject validation
    at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:229)
    at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:82)
    ... 27 more
    Caused by: org.opensaml.common.SAMLException: Local entity is not the intended audience of the assertion in at least one AudienceRestriction
    at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAudience(WebSSOProfileConsumerImpl.java:506)
    at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAssertionConditions(WebSSOProfileConsumerImpl.java:458)
    at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAssertion(WebSSOProfileConsumerImpl.java:303)
    at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:214)
    ... 28 more

    What am I missing? What am I doing wrong?
    Thanks for all your help Zack.

    asked Feb 18, 2016 at 14:04

    ZaCk1231's user avatar

    The entity ID of your Spring SAML Service Provider doesn’t match Destination element in the SAML response from Okta. Compare the two values and fix the value on either Spring SAML or Okta side.

    answered Feb 18, 2016 at 16:51

    Vladimír Schäfer's user avatar

    Vladimír SchäferVladimír Schäfer

    15.3k2 gold badges50 silver badges70 bronze badges

    2

    Same issue when deploying Spring Boot app in Azure Container Instance and using Okta SAML. saml.sp=http://fqdn-of-my.domain.com:8082/saml/metadata, FQDN resolved by an AWS hosted DNS zone A record, the URL itself is accessible and downloads the spring_saml_metadata.xml.

    Caused by: org.opensaml.common.SAMLException: Local entity is not the intended audience of the assertion in at least one AudienceRestriction
            at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAudience(WebSSOProfileConsumerImpl.java:542)
            at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAssertionConditions(WebSSOProfileConsumerImpl.java:494)
            at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAssertion(WebSSOProfileConsumerImpl.java:339)
            at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:250)
            ... 53 more
    

    answered Jun 4, 2021 at 16:43

    guest's user avatar

    Update after 30 minutes: I noticed that the error went away after a rebuild and redeploy of the app!!

    With
    saml.sp=http://fqdn-of-my.domain.com:8082/saml/metadata in Spring application.properties, the SP Metadata available at the same URL was originally the below, giving error:

    <?xml version="1.0" encoding="UTF-8"?>
    <md:EntityDescriptor 
      xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" 
      ID="http___localhost_8082_saml_metadata" 
      entityID="http://localhost:8082/saml/metadata">
    

    A rebuild and redeployment of the app with Metadata as below resulted in successful handshake:

    <?xml version="1.0" encoding="UTF-8"?>
    <md:EntityDescriptor 
      xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" 
      ID="http___fqdn-of-my.domain.com_8082_saml_metadata" 
      entityID="http://fqdn-of-my.domain.com:8082/saml/metadata">
    

    I am pretty sure I had the property correctly set even when it was giving error. But anyway, a rebuild of the Dockerized Spring app and redeploy of the same in Azure ultimately fixed the problem.

    answered Jun 4, 2021 at 17:44

    guest's user avatar

    При возникновении ошибок, связанных с SAML (языком разметки декларации безопасности), следуйте инструкциям ниже.

    Как кодировать или декодировать запросы и ответы SAML

    Чтобы вам было проще устранять неполадки, воспользуйтесь инструментом кодирования и декодирования для обработки запросов и ответов SAML из файла в формате HTTP Archive Format (HAR) в словесной форме.

    Ошибки при добавлении приложения SAML

    При добавлении приложения SAML в консоль администратора может возникнуть ошибка 400.

    400 неуникальный идентификатор объекта

    Это сообщение появляется, когда вы пытаетесь добавить приложение с уже существующим идентификатором объекта.

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

    Используйте уже настроенное приложение или укажите другой идентификатор объекта.

    500 ошибки при создании приложения SAML

    При добавлении SAML-приложения в консоли администратора вы можете столкнуться с ошибками 500. Они появляются в следующих случаях:

    • В разделе Сведения о поставщике идентификационной информации Google вы нажали кнопку Скачать сертификат или Скачать метаданные, когда сервер сертификатов был недоступен.
    • Во время загрузки схемы при сопоставлении идентификатора названия или атрибута, если превышено время ожидания отклика от сервиса схем или возникли ошибки на сервере.
    • Сервис настройки поставщика услуг недоступен. Ошибка 500 возникает на последнем этапе, когда вы нажимаете Готово.

    Чтобы устранить ошибки 500 при добавлении SAML-приложения:

    При возникновении этих проблем подождите немного и повторите попытку. Если ошибку устранить не удалось, обратитесь в службу поддержки Google Cloud.

    Ошибки выполнения SAML

    Если в ходе процессов, запущенных поставщиком услуг или поставщиком услуг идентификации (IdP), вы использовали систему единого входа на базе SAML, могут возникнуть следующие ошибки:

    403 app_not_configured (приложение не настроено)

    Эта ошибка может появиться в следующих случаях:

    • Приложение, соответствующее указанному в запросе идентификатору объекта, не было добавлено в консоль администратора.

    • Идентификатор объекта, указанный в запросе SAML, не соответствует ни одному из идентификаторов для существующих приложений. Если кто-либо исказил идентификатор приложения, указанный в URL от поставщика услуг идентификации, вы увидите ошибку app_not_configured.

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

    1. Убедитесь, что приложение, соответствующее идентификатору объекта в запросе, было установлено до отправки этого запроса.
    2. Удостоверьтесь, что идентификатор объекта в запросе SAML указан правильно и соответствует выбранному приложению.
    3. Убедитесь, что идентификатор поставщика услуг в URL запроса соответствует значению, указанному для приложения.

    403 app_not_configured_for_user (приложение не настроено для пользователя)

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

    Убедитесь, что значение тега saml:Issuer в запросе SAML совпадает со значением идентификатора объекта, заданным для SAML-приложения в разделе Сведения о поставщике услуг консоли администратора. Значение чувствительно к регистру.

    403 app_not_enabled_for_user (приложение не включено для пользователя)

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

    1. В списке приложений найдите SAML-приложение, из-за которого возникает ошибка.
    2. Нажмите на его название, чтобы открыть страницу настроек.
    3. Выберите Доступ пользователей.
    4. Включите приложение для всех пользователей или для нужного организационного подразделения.

    400 saml_invalid_user_id_mapping (неправильное сопоставление имени пользователя в SAML)

    Если в запросе SAML поставщик услуг отправил параметр Идентификатор названия, он должен соответствовать значению, указанному на стороне поставщика идентификационной информации. В противном случае система выдаст ошибку.

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

    1. Откройте раздел Основные сведения и проверьте параметр Идентификатор названия.
    2. Убедитесь, что он соответствует значению запроса SAML, указанному на стороне поставщика идентификационной информации.

    400 saml_invalid_sp_id (SAML неправильный идентификатор поставщика услуг)

    Ошибка возникает, если идентификатор поставщика услуг в URL указан неверно, так как был некорректно настроен или подменен.

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

    1. Откройте раздел Основные сведения и проверьте идентификатор приложения.

    2. Убедитесь, что идентификатор поставщика услуг в URL запроса соответствует значению, указанному для приложения.

    Иногда в ответ на запрос SAML приходит отказ. В этом случае может появиться одно из трех сообщений об ошибке, указанных ниже.

    Недопустимый запрос от поставщика услуг, URL ACS в запросе не соответствует настроенному

    Эта ошибка означает, что URL ACS в запросе SAML не соответствует значению, указанному для приложения в консоли администратора.

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

    1. Перейдите в раздел Сведения о поставщике услуг.

    2. Введите URL ACS, который указан в запросе SAML.

    Недопустимый идентификатор поставщика услуг идентификационной информации в URL

    Указанный в URL идентификатор поставщика идентификационной информации (зашифрованный идентификатор клиента) был искажен и является некорректным.

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

    1. Перейдите в раздел Безопасностьа затемНастройка системы единого входа для SAML-приложений.

    2. В конце URL идентификатора объекта найдите идентификатор поставщика услуг идентификационной информации.

    3. Убедитесь, что он соответствует идентификатору, указанному в URL запроса.

    Недопустимый идентификатор поставщика услуг идентификации в запросе

    URL системы единого входа со стороны поставщика услуг идентификации был искажен. Идентификатор поставщика скрытым образом изменен на идентификатор другого клиента.

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

    1. Перейдите в раздел Безопасностьа затемНастройка системы единого входа для SAML-приложений.

    2. В конце URL идентификатора объекта найдите идентификатор поставщика услуг идентификационной информации.

    3. Убедитесь, что он соответствует идентификатору, указанному в URL запроса.

    Ошибки 500 при тестировании системы единого входа на базе SAML

    Когда пользователи выполняют аутентификацию в системе единого входа на базе SAML через поставщика услуг или поставщика услуг идентификационной информации, они могут столкнуться с одной из ошибок 500 из-за недоступности сервера.

    Чтобы устранить ошибки 500 при тестировании системы единого входа на базе SAML:

    При возникновении этих ошибок подождите немного и повторите попытку. Если неполадку устранить не удалось, обратитесь в службу поддержки Google Cloud.

    Сообщения об ошибках доступа к приложениям SAML

    1000 ошибка доступа к приложению SAML

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

    Обратитесь в службу поддержки Google Cloud.

    1000 ошибка доступа к настройкам приложения SAML

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

    Обратитесь в службу поддержки Google Cloud.

    Сообщение об ошибке в приложении SAML при удалении схемы пользователя

    400

    Эта ошибка возникает, если вы пытаетесь удалить специальную схему, которая выполняет роль сопоставления атрибутов для удаленного SAML-приложения. Ошибка 400 может возникать, если вы создали схему до устранения этой проблемы.

    Чтобы исправить ошибку, выполните следующие действия:

    Обратитесь в службу поддержки Google Cloud.

    Эта информация оказалась полезной?

    Как можно улучшить эту статью?

    This guide provides a general overview of the Security Assertion Markup Language (SAML) 2.0 Building Block along with common Single Sign-On (SSO) issues and troubleshooting techniques for the SAML authentication provider.

    If for any reason an updated/new IdP metadata XML file is uploaded in the Blackboard Learn GUI on the SAML Authentication Settings page in the Identity Provider Settings section for a SAML authentication provider, the SAML B2 and that SAML authentication provider should also be toggled Inactive/Available, while having the SAML authentication provider in ‘Active’ status, to ensure any cached IdP metadata is cleared out and the updated IdP metadata is fully utilized.

    Key terms

    The following terms and abbreviations are used throughout this guide:

    • SAML: Security Assertion Markup Language
    • IdP: Identity Provider
    • SP: Service Provider
    • ADFS: Active Directory Federation Services
    • GUI: Graphical User Interface. In the context of Blackboard Learn, this means working within the software.

    Edit SAML configuration settings

    To help troubleshoot SAML authentication issues, the SAML Building Block was updated in Q2 2017 to include these configuration settings and options:

    • Define the SAML session age limit
    • Choose a signature algorithm type
    • Regenerate certificates
    • Change the ResponseSkew value

    More on how to configure settings in the SAML Building Block

    Errors and exceptions

    SAML related errors/exceptions are captured in the following logs:

    • /usr/local/blackboard/logs/bb-services-log.txt
    • /usr/local/blackboard/logs/tomcat/stdout-stderr-<date>.log
    • /usr/local/blackboard/logs/tomcat/catalina-log.txt

    These logs should always be searched when investigating a reported SAML authentication issue.

    SAML Tracer

    With SAML 2.0 authentication troubleshooting iterations, at some point it may be necessary to confirm/view the attributes that are actually being released from the IdP and sent to Learn during the authentication process. If the attributes from the IdP are NOT encrypted in the SAML response, the Firefox browser SAML tracer Add-on or Chrome SAML Message Decoder can be used to view the attributes.

    Attribute not properly mapped

    If the attribute containing the userName is not properly mapped as specified in the Remote User ID field in the Map SAML Attributes section on the SAML Authentication Settings page in the Blackboard Learn GUI, the following event will be logged in the bb-services log when attempting to login to Blackboard Learn via SAML authentication:

    2016-06-28 12:48:12 -0400 — userName is null or empty

    A similar Sign On Error! message displayed in the browser: Blackboard Learn is currently unable to log into your account using single-sign on. Contact your administrator for assistance.

    An Authentication Failure entry appears in the bb-services log:

    2016-06-28 12:48:12 -0400 — BbSAMLExceptionHandleFilter — javax.servlet.ServletException: Authentication Failure
     at blackboard.auth.provider.saml.customization.handler.BbAuthenticationSuccessHandler.checkAuthenticationResult(BbAuthenticationSuccessHandler.java:81)
     at blackboard.auth.provider.saml.customization.handler.BbAuthenticationSuccessHandler.onAuthenticationSuccess(BbAuthenticationSuccessHandler.java:57)
     at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.successfulAuthentication(AbstractAuthenticationProcessingFilter.java:331)
     at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:245)
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
     at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
     at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
     at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
     at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
     at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
     at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
     at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
     at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
     at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
     at java.lang.reflect.Method.invoke(Method.java:497)
     [SNIP]

    Resolution

    You have two options to resolve the issue. First, select the Create accounts if they don’t exist in the system option on the SAML Authentication Settings page in the Blackboard Learn GUI. Alternatively, you can attempt to view the value of the attributes released by the IdP via SAML tracer or Debug Logging if the attributes are NOT encrypted:

    <saml2:Attribute Name=»urn:oid:0.9.2342.19200300.100.1.3″>
        <saml2:AttributeValue xmlns:xs=»http://www.w3.org/2001/XMLSchema»
                              xmlns:xsi=»http://www.w3.org/2001/XMLSchema-instance»
                              xsi:type=»xs:anyType»
                              >[email protected]</saml2:AttributeValue>
    </saml2:Attribute>

    and map the Attribute Name that has the desired AttributeValue to the Remote User ID on the SAML Authentication Settings page in the Blackboard Learn GUI.

    Compatible data source not selected

    Users won’t be able to login to Blackboard Learn via SAML authentication if the Data Source for the users is not selected in the Services Provider Settings > Compatible Data Sources section on the SAML Authentication Settings page in the Blackboard Learn GUI. The following event will be logged in the bb-services log when attempting to log in to Blackboard Learn via SAML authentication:

    2016-09-23 12:33:13 -0500 — userName is null or empty

    The Sign On Error! message appears in the browser, as well as the Authentication Failure in the bb-services log:

    2016-09-23 12:33:13 -0500 — BbSAMLExceptionHandleFilter — javax.servlet.ServletException: Authentication Failure
            at blackboard.auth.provider.saml.customization.handler.BbAuthenticationSuccessHandler.checkAuthenticationResult(BbAuthenticationSuccessHandler.java:82)
            at blackboard.auth.provider.saml.customization.handler.BbAuthenticationSuccessHandler.onAuthenticationSuccess(BbAuthenticationSuccessHandler.java:58)
            at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.successfulAuthentication(AbstractAuthenticationProcessingFilter.java:331)
            at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:245)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
            at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
            at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
            at sun.reflect.GeneratedMethodAccessor3399.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.lang.reflect.Method.invoke(Method.java:498)
            [SNIP]

    Resolution

    1. Obtain the username of a user that is unable to login.
    2. In the Blackboard Learn GUI, navigate to System Admin > Users and search for the user.
    3. Copy the Data Source Key of the user.
    4. Navigate to System Admin > Authentication > «Provider Name» > SAML Settings > Compatible Data Sources.
    5. Place a check mark next to that Data Source in the Name column and select Submit.

    «Given URL is not well formed» error message

    If OneLogin is configured as the IdP for the SAML authentication provider in Blackboard Learn, a Given URL is not well formed error may be displayed on the page after entering the OneLogin credentials when attempting login to Blackboard Learn.

    With the following displayed in the bb-services-log:

    2016-09-16 09:43:40 -0400 — Given URL is not well formed<P><span class=»captionText»>For reference, the Error ID is 17500f44-7809-4b9f-a272-3bed1d1af131.</span> — java.lang.IllegalArgumentException: Given URL is not well formed
            at org.opensaml.util.URLBuilder.<init>(URLBuilder.java:120)
            at org.opensaml.util.SimpleURLCanonicalizer.canonicalize(SimpleURLCanonicalizer.java:87)
            at org.opensaml.common.binding.decoding.BasicURLComparator.compare(BasicURLComparator.java:57)
            at org.opensaml.common.binding.decoding.BaseSAMLMessageDecoder.compareEndpointURIs(BaseSAMLMessageDecoder.java:173)
            at org.opensaml.common.binding.decoding.BaseSAMLMessageDecoder.checkEndpointURI(BaseSAMLMessageDecoder.java:213)
            at org.opensaml.saml2.binding.decoding.BaseSAML2MessageDecoder.decode(BaseSAML2MessageDecoder.java:72)
            at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:105)
            at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:172)
            at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:80)
            at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
        [SNIP]
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
            at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
            at java.lang.Thread.run(Thread.java:745)
    Caused by: java.net.MalformedURLException: no protocol: {recipient}
            at java.net.URL.<init>(URL.java:593)
            at java.net.URL.<init>(URL.java:490)
            at java.net.URL.<init>(URL.java:439)
            at org.opensaml.util.URLBuilder.<init>(URLBuilder.java:77)
            … 203 more

    Resolution

    1. Turn on the Firefox browser SAML tracer and replicate the login issue.
    2. Review the beginning of the SAML POST event:

      <samlp:Response Destination=»{recipient}»
              ID=»R8afbfbfee7292613f98ad4ec4115de7c6b385be6″
              InResponseTo=»a3g2424154bb0gjh3737ii66dadbff4″
              IssueInstant=»2016-09-16T18:49:09Z»
              Version=»2.0″
              xmlns:saml=»urn:oasis:names:tc:SAML:2.0:assertion»
              xmlns:samlp=»urn:oasis:names:tc:SAML:2.0:protocol»
              >
          <saml:Issuer>https://app.onelogin.com/saml/metadata/123456</saml:Issuer>
          [SNIP]

    3. For line 1 with the Response, observe that the Destination= is only set to recipient.
    4. Have the client access the Configuration section of their OneLogin IdP.
    5. Confirm if the Recipient field is blank.
    6. Copy the value of the ACS (Consumer) URL, paste it into the Recipient field and select Save.

    IdP/SP Problem Scenarios

    1. If an error appears before you are redirected to the IdP’s login page, the IdP’s metadata may be invalid.
    2. If an error appears after you log in on the IdP’s page, the reasons could be that:
      1. Attribute mapping between the SP and IdP is incorrect, or the IdP didn’t return a valid Remote User ID.
      2. The SAML response from the IdP wasn’t validated by the SP. This could be caused by:
        • The IdP signs the SAML response with a certificate that is not issued by a valid certificate authority, and the SP’s keystore doesn’t contain this certificate.
        • The SP’s system clock is incorrect.

    Active Directory Federation Services (ADFS)

    The attribute names are case sensitive in the Map SAML Attributes section on the SAML Authentication Settings page in the Blackboard Learn GUI. So if the Remote User ID has sAMAccountName for the Attribute Name on the settings page and the actual SAML POST from the IdP has this for the Attribute Name in the AttributeStatement:

    <AttributeStatement>
        <Attribute Name=»SamAccountName>
            <AttributeValue>Test-User</AttributeValue>
        </Attribute>
    </AttributeStatement>

    The user will not be able to login. The Remote User ID attribute name value on the SAML Authentication Settings page would need to be changed from sAMAccountName to SamAccountName.

    «Resource not found» or «Sign on error!» warning

    This section contains some of the common problems that may prevent a user from logging into Learn via SAML authentication with ADFS when The specified resource was not found, or you do not have permission to access it or Sign On Error! message is displayed in the Blackboard Learn GUI.

    Problem #1

    After entering the login credentials on the ADFS login page, an error may be displayed after being redirected to the Blackboard Learn GUI: The specified resource was not found, or you do not have permission to access it.

    With a corresponding message in the stdout-stderr log:

    INFO | jvm 1 | 2016/06/22 06:08:33 | — No mapping found for HTTP request with URI [/auth-saml/saml/SSO] in DispatcherServlet with name ‘saml’

    The problem occurs because the noHandlerFound() method is used in the DispatcherServlet.java code and is unable to locate/map the HTTP SSO request.

    /**
     * No handler found -> set appropriate HTTP response status.
     * @param request current HTTP request
     * @param response current HTTP response
     * @throws Exception if preparing the response failed
     */
    protected void noHandlerFound(HttpServletRequest request, HttpServletResponse response) throws Exception {
     if (pageNotFoundLogger.isWarnEnabled()) {
      pageNotFoundLogger.warn(«No mapping found for HTTP request with URI [» + getRequestUri(request) +
        «] in DispatcherServlet with name ‘» + getServletName() + «‘»);
     }
     if (this.throwExceptionIfNoHandlerFound) {
      throw new NoHandlerFoundException(request.getMethod(), getRequestUri(request),
        new ServletServerHttpRequest(request).getHeaders());
     }
     else {
      response.sendError(HttpServletResponse.SC_NOT_FOUND);
     }
    }

    Resolution

    This typically occurs because the Entity ID for the SP configured in the Blackboard Learn GUI is incorrect. This can be resolved by navigating to System Admin > Authentication > SAML Authentication Settings > Service Provider Settings and updating the Entity ID. For ADFS, the default configuration for the Entity ID would be https://[Learn Server Hostname]/auth-saml/saml/SSO.

    If a school changes their URL from the default https://school.blackboard.com to https://their.school.edu, the Entity ID in the Blackboard Learn GUI on the SAML Authentication Settings page should be updated to https://their.school.edu/auth-saml/saml/SSO.

    Problem #2

    After entering the login credentials on the ADFS login page, an error may be displayed after being redirected to the Blackboard Learn GUI: The specified resource was not found, or you do not have permission to access it.

    With this corresponding message in the stdout-stderr log:

    INFO  | jvm 1  | 2016/06/22 06:08:33 | — No mapping found for HTTP request with URI [/auth-saml/saml/SSO] in DispatcherServlet with name ‘saml’

    And this message in the catalina log:

    ERROR 2016-06-27 10:47:03,664 connector-6: userId=_2_1, sessionId=62536416FB80462298C92064A7022E50 org.opensaml.xml.encryption.Decrypter — Error decrypting the encrypted data element
    org.apache.xml.security.encryption.XMLEncryptionException: Illegal key size
    Original Exception was java.security.InvalidKeyException: Illegal key size
            at org.apache.xml.security.encryption.XMLCipher.decryptToByteArray(XMLCipher.java:1822)
            at org.opensaml.xml.encryption.Decrypter.decryptDataToDOM(Decrypter.java:596)
            at org.opensaml.xml.encryption.Decrypter.decryptUsingResolvedEncryptedKey(Decrypter.java:795)
            at org.opensaml.xml.encryption.Decrypter.decryptDataToDOM(Decrypter.java:535)
            at org.opensaml.xml.encryption.Decrypter.decryptDataToList(Decrypter.java:453)
            at org.opensaml.xml.encryption.Decrypter.decryptData(Decrypter.java:414)
            at org.opensaml.saml2.encryption.Decrypter.decryptData(Decrypter.java:141)
            at org.opensaml.saml2.encryption.Decrypter.decrypt(Decrypter.java:69)
            at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:199)
            at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:82)
            at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
            [SNIP]
            at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
            at java.lang.Thread.run(Thread.java:745)
    Caused by: java.security.InvalidKeyException: Illegal key size
            at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1039)
            at javax.crypto.Cipher.init(Cipher.java:1393)
            at javax.crypto.Cipher.init(Cipher.java:1327)
            at org.apache.xml.security.encryption.XMLCipher.decryptToByteArray(XMLCipher.java:1820)
            … 205 more

    And this message displayed in the bb-services log:

    2016-06-27 10:47:03 -0400 — unsuccessfulAuthentication — org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
            at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100)
            at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
            at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
            at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
            at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
            at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
            at sun.reflect.GeneratedMethodAccessor3422.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.lang.reflect.Method.invoke(Method.java:498)
            at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:277)
            at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:274)
            at java.security.AccessController.doPrivileged(Native Method)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
            at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:309)
            at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:249)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
            at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:55)
            at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:191)
            at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:187)
            at java.security.AccessController.doPrivileged(Native Method)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:186)
            at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:30)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at sun.reflect.GeneratedMethodAccessor3421.invoke(Unknown Source)
            [SNIP]
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
            at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
            at java.lang.Thread.run(Thread.java:745)
    Caused by: org.opensaml.common.SAMLException: Response doesn’t have any valid assertion which would pass subject validation
            at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:229)
            at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87)
            … 229 more

    The problem occurs because by default ADFS encrypts the attributes it sends using AES-256 and the Java runtime used by Blackboard Learn doesn’t support AES-256 out of the box.

    Resolution

    A universal resolution option is to open a PowerShell on the ADFS server and set the relying party created for Blackboard Learn to send the attributes as unencrypted. As the whole communication is over SSL, this will not reduce the security of the authentication. It also makes debugging of any issues easier as the attributes can be viewed using debugging tools such as the Firefox browser SAML tracer Add-on and a restart of the Blackboard Learn system is not required. To set the relying party created for Blackboard Learn to send the attributes as unencrypted, open a PowerShell and execute the following command, replacing TargetName with the name of the Relying Party Trust that is in the ADFS Management Console under Trust Relationships > Relying Party Trusts.

    set-ADFSRelyingPartyTrust –TargetName «yourlearnserver.blackboard.com» –EncryptClaims $False

    After this change the ADFS service will need to be restarted with the command: Restart-Service ADFSSRV

    Problem #3

    After entering the login credentials on the ADFS login page, an error may be displayed after being redirected to the Blackboard Learn GUI: The specified resource was not found, or you do not have permission to access it or Sign On Error!

    With either, these similar corresponding SAML related events appear in the stdout-stderr log:

    INFO   | jvm 1    | 2016/09/06 20:33:04 | — /saml/login?apId=_107_1&redirectUrl=https%3A%2F%2Fbb.fraser.misd.net%2Fwebapps%2Fportal%2Fexecute%2FdefaultTab at position 1 of 10 in additional filter chain; firing Filter: ‘SecurityContextPersistenceFilter’
    INFO   | jvm 1    | 2016/09/06 20:33:04 | — No HttpSession currently exists
    INFO   | jvm 1    | 2016/09/06 20:33:04 | — No SecurityContext was available from the HttpSession: null. A new one will be created.
    INFO   | jvm 1    | 2016/09/06 20:33:04 | — /saml/login?apId=_107_1&redirectUrl=https%3A%2F%2Fbb.fraser.misd.net%2Fwebapps%2Fportal%2Fexecute%2FdefaultTab at position 2 of 10 in additional filter chain; firing Filter: ‘WebAsyncManagerIntegrationFilter’
    INFO   | jvm 1    | 2016/09/06 20:33:04 | — /saml/login?apId=_107_1&redirectUrl=https%3A%2F%2Fbb.fraser.misd.net%2Fwebapps%2Fportal%2Fexecute%2FdefaultTab at position 3 of 10 in additional filter chain; firing Filter: ‘HeaderWriterFilter’
    INFO   | jvm 1    | 2016/09/06 20:33:04 | — /saml/login?apId=_107_1&redirectUrl=https%3A%2F%2Fbb.fraser.misd.net%2Fwebapps%2Fportal%2Fexecute%2FdefaultTab at position 4 of 10 in additional filter chain; firing Filter: ‘FilterChainProxy’
    INFO   | jvm 1    | 2016/09/06 20:33:04 | — Checking match of request : ‘/saml/login’; against ‘/saml/login/**’
    INFO   | jvm 1    | 2016/09/06 20:33:04 | — /saml/login?apId=_107_1&redirectUrl=https%3A%2F%2Fbb.fraser.misd.net%2Fwebapps%2Fportal%2Fexecute%2FdefaultTab at position 1 of 1 in additional filter chain; firing Filter: ‘SAMLEntryPoint’
    INFO   | jvm 1    | 2016/09/06 20:33:04 | — Request for URI http://www.w3.org/2000/09/xmldsig#rsa-sha1
    INFO   | jvm 1    | 2016/09/06 20:33:04 | — Request for URI http://www.w3.org/2000/09/xmldsig#rsa-sha1
    INFO   | jvm 1    | 2016/09/06 20:33:04 | — SecurityContext is empty or contents are anonymous — context will not be stored in HttpSession.
    INFO   | jvm 1    | 2016/09/06 20:33:04 | — SecurityContextHolder now cleared, as request processing completed
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — /saml/SSO at position 1 of 10 in additional filter chain; firing Filter: ‘SecurityContextPersistenceFilter’
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — HttpSession returned null object for SPRING_SECURITY_CONTEXT
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — No SecurityContext was available from the HttpSession: [email protected] A new one will be created.
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — /saml/SSO at position 2 of 10 in additional filter chain; firing Filter: ‘WebAsyncManagerIntegrationFilter’
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — /saml/SSO at position 3 of 10 in additional filter chain; firing Filter: ‘HeaderWriterFilter’
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — /saml/SSO at position 4 of 10 in additional filter chain; firing Filter: ‘FilterChainProxy’
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — Checking match of request : ‘/saml/sso’; against ‘/saml/login/**’
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — Checking match of request : ‘/saml/sso’; against ‘/saml/logout/**’
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — Checking match of request : ‘/saml/sso’; against ‘/saml/bbsamllogout/**’
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — Checking match of request : ‘/saml/sso’; against ‘/saml/sso/**’
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — /saml/SSO at position 1 of 1 in additional filter chain; firing Filter: ‘SAMLProcessingFilter’
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — Authentication attempt using org.springframework.security.saml.SAMLAuthenticationProvider
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — Forwarding to /
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — DispatcherServlet with name ‘saml’ processing POST request for [/auth-saml/saml/SSO]
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — No mapping found for HTTP request with URI [/auth-saml/saml/SSO] in DispatcherServlet with name ‘saml’
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — SecurityContext is empty or contents are anonymous — context will not be stored in HttpSession.
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — Successfully completed request
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — Skip invoking on
    INFO   | jvm 1    | 2016/09/06 20:33:07 | — SecurityContextHolder now cleared, as request processing completed

    Or these similar SAML exceptions in the bb-services log:

    2016-11-29 09:04:24 -0500 — unsuccessfulAuthentication — org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
            at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100)
            at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
            at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
            at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
            at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
            at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
            at sun.reflect.GeneratedMethodAccessor853.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.lang.reflect.Method.invoke(Method.java:498)
            at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:282)
            at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:279)
            at java.security.AccessController.doPrivileged(Native Method)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
            at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314)
            at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
            at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:46)
            at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:148)
            at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:144)
            at java.security.AccessController.doPrivileged(Native Method)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:143)
            at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:30)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at sun.reflect.GeneratedMethodAccessor853.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            [SNIP]
            at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:677)
            at blackboard.tomcat.valves.LoggingRemoteIpValve.invoke(LoggingRemoteIpValve.java:44)
            at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
            at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)
            at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:1110)
            at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
            at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:785)
            at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1425)
            at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
            at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
            at java.lang.Thread.run(Thread.java:745)
    Caused by: org.opensaml.common.SAMLException: Response issue time is either too old or with date in the future, skew 60, time 2016-11-29T14:03:16.634Z
            at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:126)
            at blackboard.auth.provider.saml.customization.consumer.BbSAMLWebSSOProfileConsumerImpl.processAuthenticationResponse(BbSAMLWebSSOProfileConsumerImpl.java:40)
            at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87)
            … 230 more

    The problem occurs when the ADFS server and the Blackboard Learn application server have a time drift close to or beyond the default of 60 seconds.

    Resolution

    There are two options to resolve the issue:

    1. Manually syncing the clocks of the Blackboard Learn application servers and the ADFS server. For Blackboard Learn, the current time and time zone of the server can be viewed in a web browser by adding /webapps/blackboard/amiup.jsp to the end of a Blackboard Learn URL.

      Example: https://mhtest1.blackboard.com/webap…oard/amiup.jsp

      Yes database : Thu Dec 08 17:13:32 EST 2016 : HOSTNAME=fgprd-523885-sf160752-app001

      An institution may use one of the above URLs to compare the Blackboard Learn system time zone and clock with that of their ADFS server and then adjust those items as necessary on the ADFS server so that they are in-sync with the Blackboard Learn site.

    2. The skew can be adjusted in the securityContext.xml to workaround the issue:
      1. Make a backup copy of the file:

        /usr/local/blackboard/content/vi/BBLEARN/plugins/bb-auth-provider-saml/webapp/WEB-INF/config/saml/securityContext.xml

      2. Change:

        <!— SAML 2.0 WebSSO Assertion Consumer —>
        <bean id=»webSSOprofileConsumer» class=»org.springframework.security.saml.websso.WebSSOProfileConsumerImpl»/>

        to:

        <!— SAML 2.0 WebSSO Assertion Consumer —>
        <bean id=»webSSOprofileConsumer» class=»org.springframework.security.saml.websso.WebSSOProfileConsumerImpl»>
        <property name=»responseSkew»value=»60000″/><!— 100 hours —>
        </bean>

    Problem #4

    After entering the login credentials on the ADFS login page, an error may be displayed after being redirected to the Blackboard Learn GUI: The specified resource was not found, or you do not have permission to access it or Sign On Error!

    With the following exceptions in the bb-services log:

    2016-11-01 12:47:19 -0500 — unsuccessfulAuthentication — org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
            at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100)
            at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
            at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
            at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
            at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
            at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
            at sun.reflect.GeneratedMethodAccessor929.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.lang.reflect.Method.invoke(Method.java:498)
            at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:282)
            at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:279)
            at java.security.AccessController.doPrivileged(Native Method)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
            at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314)
            at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
            at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:46)
            at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:148)
            at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:144)
            at java.security.AccessController.doPrivileged(Native Method)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:143)
            at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:30)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
     [SNIP]
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
            at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
            at java.lang.Thread.run(Thread.java:745)
    Caused by: org.opensaml.common.SAMLException: Response has invalid status code urn:oasis:names:tc:SAML:2.0:status:Responder, status message is null
            at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:113)
            at blackboard.auth.provider.saml.customization.consumer.BbSAMLWebSSOProfileConsumerImpl.processAuthenticationResponse(BbSAMLWebSSOProfileConsumerImpl.java:40)
            at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87)
            … 230 more
     2016-11-01 12:47:19 -0500 — BbSAMLExceptionHandleFilter — javax.servlet.ServletException: Unsuccessful Authentication
             at blackboard.auth.provider.saml.customization.filter.BbSAMLProcessingFilter.unsuccessfulAuthentication(BbSAMLProcessingFilter.java:31)
             at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:235)
             at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
             at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
             at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
             at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
             at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
             at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
             at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
             at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
             at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
             at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
             at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
             at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
             at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
             at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
             at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
             at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
             at sun.reflect.GeneratedMethodAccessor929.invoke(Unknown Source)
             at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
             at java.lang.reflect.Method.invoke(Method.java:498)
             at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:282)
             at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:279)
             at java.security.AccessController.doPrivileged(Native Method)
             at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
             at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314)
             at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253)
             at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
             at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:46)
             at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:148)
             at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:144)
             at java.security.AccessController.doPrivileged(Native Method)
             at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:143)
             at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:30)
     [SNIP]

    Resolution

    In Blackboard Learn 9.1 Q2 2017 and later, this option can be configured in the user interface.

    1. Navigate to the Admin Panel.
    2. Under Building Blocks, select Building Blocks.
    3. Select Installed Tools.
    4. Locate Authentication Provider — SAML in the list. Open the menu and select Settings.
    5. Under Signature Algorithm Settings, choose SHA-256 in the list. After you select the Signature Algorithm Type, restart the SAML building block to apply the new settings.
    6. Select Submit to save your changes.

    For Blackboard Learn 9.1 Q4 2016 and earlier, you can adjust the SHA option as follows.

    The authentication requests are encrypted between Blackboard Learn and ADFS using the SHA-256 algorithm, which is used by default for MS ADFS as its base encryption.

    1. In the ADFS management console, right-click the Relying Party Trust.
    2. Select Properties.
    3. Select the Advanced Tab.
    4. Change the Security hash algorithm from SHA-256 (ADFS Default) to SHA-1.
    5. Select OK.

    Problem #5

    After entering the login credentials on the ADFS login page, an error may be displayed after being redirected to the Blackboard Learn GUI: The specified resource was not found, or you do not have permission to access it or Sign On Error!

    With the following exceptions in the bb-services log:

    2017-01-04 22:52:58 -0700 — unsuccessfulAuthentication — org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
            at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100)
            at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
            at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
            at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
            at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
            at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
            at sun.reflect.GeneratedMethodAccessor935.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.lang.reflect.Method.invoke(Method.java:498)
            at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:282)
            at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:279)
            at java.security.AccessController.doPrivileged(Native Method)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
            at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314)
            at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
            at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:46)
            at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:148)
            at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:144)
            at java.security.AccessController.doPrivileged(Native Method)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:143)
            at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:30)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        [SNIP]
            at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
            at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
            at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
            at java.lang.Thread.run(Thread.java:745)
    Caused by: org.opensaml.common.SAMLException: NameID element must be present as part of the Subject in the Response message, please enable it in the IDP configuration
            at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:252)
            at blackboard.auth.provider.saml.customization.consumer.BbSAMLWebSSOProfileConsumerImpl.processAuthenticationResponse(BbSAMLWebSSOProfileConsumerImpl.java:40)
            at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87)
            … 214 more

    As stated in the above SAML exception, the NameID element is missing from the Subject in the Response message. The problem typically occurs when the NameID is not setup as an Outgoing Claim Type in a Claims Rule for the Relying Party Trust on the institution’s ADFS IdP or the Claims Rule for the NameID is not in the proper order for the Relying Party Trust on the institution’s ADFS IdP, which in turn causes the missing NameID element in the Subject in the Response message.

    Example: NameID element is missing

    <Subject>
        <SubjectConfirmation Method=»urn:oasis:names:tc:SAML:2.0:cm:bearer»>
            <SubjectConfirmationData InResponseTo=»a22ai8iig0f75ae22hd28748b12da50″
                                     NotOnOrAfter=»2017-01-03T05:57:58.234Z»
                                     Recipient=»https://yourschool.blackboard.com/auth-saml/saml/SSO»
                                     />
        </SubjectConfirmation>
    </Subject>

    Example: NameID element is present

    <Subject>
        <NameID Format=»urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress»>testadfs</NameID>
        <SubjectConfirmation Method=»urn:oasis:names:tc:SAML:2.0:cm:bearer»>
            <SubjectConfirmationData InResponseTo=»a5903d39if463ea87ieiab5135j9ji»
                                     NotOnOrAfter=»2017-01-05T04:33:12.715Z»
                                     Recipient=»https://yourschool.blackboard.com/auth-saml/saml/SSO»
                                     />
        </SubjectConfirmation>
    </Subject>

    You can use the Firefox SAML tracer Add-on to view the Subject in the Response message.

    Resolution

    There are three methods to resolving this issue.

    1. Confirm the steps from the SAML B2 Setup Guide for ADFS were properly followed and make changes as needed to transform an incoming claim for the Relying Party Trust for their ADFS IdP:
      1. Select Edit Claims Rule.
      2. Select Add Rule.
      3. On the Select Rule Template page, select Transform an Incoming Claim for the Claim rule template and then select Next.
      4. On the Configure Rule page, in the Claim rule name field, type Transform Email to Name ID.
      5. Incoming claim type should be SamAccountName (it must match the Outgoing Claim Type created initially in the Transform Username to NameID rule).
      6. The Outgoing claim type is Name ID.
      7. The Outgoing name ID format is Email.
      8. Confirm Pass through all claim values is selected and select Finish.
      9. Select OK to save the rule and OK again to complete the attribute mappings.
    2. Ensure for the order of the Claims Rules used for their ADFS IdP that the rule which has the NameID element does not have any optional rules occurring before it.
    3. If using a custom attribute, ensure the NameID element is in the Relying Party Trust since Learn still expects that their ADFS IdP release a NameID value.

    Problem #6

    When logged into Blackboard Learn via SAML authentication, the user attempts to log out by clicking on the Sign Out button on the left side of the page and then clicks the End SSO Session button, a Sign On Error! is immediately displayed.

    Sign On Error!
    Blackboard Learn is currently unable to log into your account using single sign-on. Contact your administrator for assistance.
    For reference, the Error ID is [error ID].

    With the following exception in the bb-services log:

    2017-05-08 15:10:46 -0400 — BbSAMLExceptionHandleFilter Error Id: f3299757-8d4e-4fab-98cf-49cd99f4891e — javax.servlet.ServletException: Incoming SAML message failed security validation
        at org.springframework.security.saml.SAMLLogoutProcessingFilter.processLogout(SAMLLogoutProcessingFilter.java:145)
        at org.springframework.security.saml.SAMLLogoutProcessingFilter.doFilter(SAMLLogoutProcessingFilter.java:104)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
        [SNIP]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)
    Caused by: org.opensaml.ws.security.SecurityPolicyException: Validation of request simple signature failed for context issuer
        at org.opensaml.common.binding.security.BaseSAMLSimpleSignatureSecurityPolicyRule.doEvaluate(BaseSAMLSimpleSignatureSecurityPolicyRule.java:139)
        at org.opensaml.common.binding.security.BaseSAMLSimpleSignatureSecurityPolicyRule.evaluate(BaseSAMLSimpleSignatureSecurityPolicyRule.java:103)
        at org.opensaml.ws.security.provider.BasicSecurityPolicy.evaluate(BasicSecurityPolicy.java:51)
        at org.opensaml.ws.message.decoder.BaseMessageDecoder.processSecurityPolicy(BaseMessageDecoder.java:132)
        at org.opensaml.ws.message.decoder.BaseMessageDecoder.decode(BaseMessageDecoder.java:83)
        at org.opensaml.saml2.binding.decoding.BaseSAML2MessageDecoder.decode(BaseSAML2MessageDecoder.java:70)
        at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:105)
        at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:172)
        at org.springframework.security.saml.SAMLLogoutProcessingFilter.processLogout(SAMLLogoutProcessingFilter.java:131)
        … 244 more

    The error occurs because of the Single Logout Service Type setting on the SAML Settings page.

    Resolution

    The setting needs to be configured in Blackboard Learn and on the ADFS server.

    For ADFS as the IdP, select the Post setting only and remove the Redirect endpoint for the Learn instance’s Relying Party Trust on the ADFS server.

    1. In Learn, navigate to Admin > Authentication > (Provider Name) > SAML Settings > Single Logout Service Type.
    2. Select Post and clear the Redirect checkbox.
    3. In the ADFS Server, go into the Relying Party Trust for your Learn Instance.
    4. Select Properties > Endpoints. Two SAML logout endpoints are listed.
    5. Remove the Redirect endpoint. Select Remove Endpoint to remove it, then Apply and OK.

    After making the above changes in Learn and the ADFS server, the End SSO Session logout button will work to properly sign out the user.

    Problem #7

    After entering the login credentials on the ADFS login page, a Sign On Error! message is displayed when redirected to Learn.

    With the following SAML exception in the bb-services log:

    2017-05-26 07:39:30 -0400 — unsuccessfulAuthentication — org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
            at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100)
            at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
            at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
            at blackboard.auth.provider.saml.customization.filter.BbSAMLProcessingFilter.attemptAuthentication(BbSAMLProcessingFilter.java:46)
            at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
            at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
            at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
            at sun.reflect.GeneratedMethodAccessor380.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.lang.reflect.Method.invoke(Method.java:498)
            at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:282)
            at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:279)
            at java.security.AccessController.doPrivileged(Native Method)
            at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
            at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314)
            at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253)
            at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
            at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:46)
            at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:148)
            at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:144)
            at java.security.AccessController.doPrivileged(Native Method)
            at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:143)
            at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:37)
        [SNIP]
            at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
            at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
            at java.lang.Thread.run(Thread.java:745)
    Caused by: org.opensaml.common.SAMLException: Response has invalid status code urn:oasis:names:tc:SAML:2.0:status:Responder, status message is null
            at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:113)
            at blackboard.auth.provider.saml.customization.consumer.BbSAMLWebSSOProfileConsumerImpl.processAuthenticationResponse(BbSAMLWebSSOProfileConsumerImpl.java:56)
            at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87)
            … 247 more

    Resolution

    Beginning in Learn Q2 2017, there is now an option to regenerate the SAML encryption certificate by navigating to System Admin > Building Blocks > Authentication Provider — SAML > Settings > Regenerate Certificate. The Sign On Error! problem may occur if the Regenerate certificate button is selected after the SP metadata is already uploaded to the Relying Party Trust for the Learn site on the ADFS server. To resolve the issue:

    1. Navigate to System Admin > Authentication > [SAML Provider Name] > SAML Settings.
    2. Select Generate next to Service Provider Metadata to save the new metadata file.
    3. Access your ADFS server and upload the new SP metadata to the Relying Party Trust for your Learn site.

    If you generate a new certificate under the B2 settings, you need to toggle the SAML B2 to Inactive and then back to Active to force the change. After, you can return to the provider settings and generate the new metadata to import into the IDP. If you don’t toggle the settings, the old certificate may still be included when you generate new metadata. The IDP won’t be updated and the next time Learn restarts it will present the new certificate. SAML authentication will break because of this mismatch.

    Federation Metadata

    With Active Directory Federation Services (ADFS), since the metadata for an ADFS federation typically located in https://[ADFS Server Hostname]/FederationMetadata/2007-06/FederationMetadata.xml includes an element that is incompatible with SAML 2.0, the metadata needs to be edited to delete the incompatible element before it is uploaded to the Identity Provider Settings section on the SAML Authentication Settings page in the Blackboard Learn GUI. If the metadata with the incompatible element is uploaded, an error will occur when selecting the SAML login link on the Blackboard Learn login page: Metadata for entity and role wasn’t found. For reference, the Error ID is [error ID].

    And the corresponding Java stack trace for the Error ID in the bb-services log has the following:

    2016-06-21 11:42:51 -0700 — Metadata for entity https://<Learn Server Hostname>/adfs/ls/ and role {urn:oasis:names:tc:SAML:2.0:metadata}SPSSODescriptor wasn't found<P><span class=»captionText»>For reference, the Error ID is c99511ae-1162-4941-b823-3dda19fea157.</span> — org.opensaml.saml2.metadata.provider.MetadataProviderException: Metadata for entity https://ulvsso.laverne.edu/adfs/ls/ and role {urn:oasis:names:tc:SAML:2.0:metadata}SPSSODescriptor wasn’t found
            at org.springframework.security.saml.context.SAMLContextProviderImpl.populateLocalEntity(SAMLContextProviderImpl.java:319)
            at org.springframework.security.saml.context.SAMLContextProviderImpl.populateLocalContext(SAMLContextProviderImpl.java:216)
            at org.springframework.security.saml.context.SAMLContextProviderImpl.getLocalAndPeerEntity(SAMLContextProviderImpl.java:126)
            at org.springframework.security.saml.SAMLEntryPoint.commence(SAMLEntryPoint.java:146)
            at org.springframework.security.saml.SAMLEntryPoint.doFilter(SAMLEntryPoint.java:107)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
            at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
            at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
            at sun.reflect.GeneratedMethodAccessor1652.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.lang.reflect.Method.invoke(Method.java:498)
            [SNIP]

    Resolution

    Since the default metadata location for an ADFS federation is https://[ADFS server hostname]/FederationMetadata/2007-06/FederationMetadata.xml:

    1. Download this file and open it in a text editor. Carefully delete the section starting <ds:Signature xmlns:ds=»http://www.w3.org/2000/09/xmldsig#»> … </X509Data></KeyInfo> and ending </ds:Signature>
      <ds:Signature xmlns:ds=»http://www.w3.org/2000/09/xmldsig#»>

      <ds:SignedInfo>
        <ds:CanonicalizationMethod Algorithm=»http://www.w3.org/2001/10/xml-exc-c14n#»/>
        <ds:SignatureMethod Algorithm=»http://www.w3.org/2001/04/xmldsig-more#rsa-sha256″/>
        <ds:Reference URI=»#_43879f32-9a91-4862-bc87-e98b85b51158″>
         <ds:Transforms>
          <ds:Transform Algorithm=»http://www.w3.org/2000/09/xmldsig#enveloped-signature»/>
          <ds:Transform Algorithm=»http://www.w3.org/2001/10/xml-exc-c14n#»/>
         </ds:Transforms>
         <ds:DigestMethod Algorithm=»http://www.w3.org/2001/04/xmlenc#sha256″/>
         <ds:DigestValue>z1H1[SNIP]jaYM=</ds:DigestValue>
        </ds:Reference>
        </ds:SignedInfo>
        <ds:SignatureValue> FVj[SNIP]edrfNKWvsvk5A==
        </ds:SignatureValue>
        <KeyInfo xmlns=»http://www.w3.org/2000/09/xmldsig#»>
         <X509Data>
          <X509Certificate>
          FDdd[SNIP]qTNKdk5F/vf1AocDaX
          </X509Certificate>
         </X509Data>
        </KeyInfo>
      </ds:Signature>

    2. Upload the updated metadata XML file in the Blackboard Learn GUI on the SAML Authentication Settings page in the Identity Provider Settings section.
    3. Toggle the SAML authentication provider and SAML B2 Inactive/Available, while having the SAML authentication provider in ‘Active’ status.

    If an institution is testing SAML authentication on a Blackboard Learn site and has multiple SAML authentication providers that share the same underlying ADFS IdP metadata XML file on the Blackboard Learn site, even if the other SAML authentication providers are set to Inactive, they will also need to have the updated metadata XML file uploaded in the Blackboard Learn GUI on the SAML Authentication Settings page in the Identity Provider Settings section. The SAML B2 should then be toggled Inactive/Available, while having the SAML authentication provider in ‘Active’ status, to ensure the updated metadata XML file is recognized system-wide.

    Incorrect user lookup method

    After entering the login credentials on the ADFS login page, the user is redirected to the Blackboard Learn GUI, but not logged into Blackboard Learn.

    The ONLY SAML authentication related event in the bb-services log is:

    2016-10-18 13:03:28 -0600 — userName is null or empty

    Resolution

    1. Login to Blackboard Learn as administrator using the default Blackboard Learn Internal authentication.
    2. Navigate to System Admin > «SAML Authentication Provider Name» > Edit.
    3. Change the User Lookup Method from Batch Uid to Username.

    Extra End SSO Session logout button

    ADFS tries to add an extra End SSO Session logout button on the End all sessions? page that is displayed after first selecting the logout button at the top right in the Blackboard Learn GUI.

    This is done by adding an extra SingleLogoutService to the IdP Metadata file:

    <SingleLogoutService Binding=»urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect» Location=»https://your.server.name/adfs/ls/»/>
    <SingleLogoutService Binding=»urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST» Location=»https://your.server.name/adfs/ls/»/>

    Since that is an optional SAML B2 IdP configuration and the signature being provided in the Redirect Endpoint is not correct, an error will occur when selecting the extra End SSO Session button on the End all sessions? page: Incoming SAML message failed security validation. Validation of request simple signature failed for context issuer. For reference, the Error ID is [error ID].

    The corresponding Java stack trace for the Error ID in the bb-services log has:

    2016-10-17 16:57:44 -0400 — Incoming SAML message failed security validation Validation of request simple signature failed for context issuer<P><span class=»captionText»>For reference, the Error ID is 930c7767-8710-475e-8415-2077152280e0.</span> — org.opensaml.ws.security.SecurityPolicyException: Validation of request simple signature failed for context issuer
            at org.opensaml.common.binding.security.BaseSAMLSimpleSignatureSecurityPolicyRule.doEvaluate(BaseSAMLSimpleSignatureSecurityPolicyRule.java:139)
            at org.opensaml.common.binding.security.BaseSAMLSimpleSignatureSecurityPolicyRule.evaluate(BaseSAMLSimpleSignatureSecurityPolicyRule.java:103)
            at org.opensaml.ws.security.provider.BasicSecurityPolicy.evaluate(BasicSecurityPolicy.java:51)
            at org.opensaml.ws.message.decoder.BaseMessageDecoder.processSecurityPolicy(BaseMessageDecoder.java:132)
            at org.opensaml.ws.message.decoder.BaseMessageDecoder.decode(BaseMessageDecoder.java:83)
            at org.opensaml.saml2.binding.decoding.BaseSAML2MessageDecoder.decode(BaseSAML2MessageDecoder.java:70)
            at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:105)
            at org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:172)
            at org.springframework.security.saml.SAMLLogoutProcessingFilter.processLogout(SAMLLogoutProcessingFilter.java:131)
            at org.springframework.security.saml.SAMLLogoutProcessingFilter.doFilter(SAMLLogoutProcessingFilter.java:104)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
            at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
            at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
            at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
            at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
            at sun.reflect.GeneratedMethodAccessor1652.invoke(Unknown Source)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.lang.reflect.Method.invoke(Method.java:498)
            [SNIP]

    Resolution

    1. Access the ADFS Server and go into the Relying Party Trust for the Blackboard Learn Instance.
    2. Select Properties > Endpoints tab.
    3. In the Endpoints tab there will be 2 SAML Logout Endpoints.
    4. Remove the Redirect endpoint.
    5. Select Remove Endpoint to remove it, then Apply and OK.

    After removing the Redirect endpoint, the End SSO Session button will work properly signing out the user.

    Viewing application logs with event viewer

    When troubleshooting an ADFS SAML authentication issue, it may be necessary to also have an institution review the ADFS application logs in the Event Viewer on their ADFS server for further insight. This is particularly necessary when the SAML response from the ADFS server has a Request Denied status as seen below:

    <samlp:Status>
        <samlp:StatusCode Value=»urn:oasis:names:tc:SAML:2.0:status:Responder»>
            <samlp:StatusCode Value=»urn:oasis:names:tc:SAML:2.0:status:RequestDenied» />
        </samlp:StatusCode>
    </samlp:Status>

    The SAML response can be viewed by using the Firefox browser SAML tracer Add-on.

    The Request Denied status in a response typically indicates a problem occurred when the IdP (ADFS) attempted to understand the response and process the result the SP (Blackboard Learn) provided.

    To view the ADFS application logs with the Event Viewer:

    1. Open the Event Viewer on the ADFS server.
    2. On the View menu, select Show Analytic and Debug Logs.
    3. In the console tree, navigate to Application and Service Logs > AD FS Tracing > Debug.

    Azure Active Directory

    Azure AD is Microsoft’s (MS) cloud based directory and identity management service.

    Send first part of email

    If an institution is using Azure AD as their IdP and wishes to only have the first part of the Azure AD email username used for the Blackboard Learn username, they can configure their Azure AD IdP to use the special ExtractMailPrefix() function to remove the domain suffix from either the email or the user principal name resulting in only the first part of the username being passed through (e.g. «joesmith» instead of [email protected]).

    If the Blackboard Learn Remote User ID is urn:oid:1.3.6.1.4.1.5923.1.1.1.6, the Attribute setting for the Azure IdP would look like this:

    Attribute Name:        urn:oid:1.3.6.1.4.1.5923.1.1.1.6
    Attribute Value:    ExtractMailPrefix()
    Mail:            user.userprincipalname

    So with the example [email protected] email username, it would be passed like this in the SAML assertion from the Azure IdP to Blackboard Learn:

    <Attribute Name=»urn:oid:1.3.6.1.4.1.5923.1.1.1.6″>
        <AttributeValue>joesmith</AttributeValue>

    Additional info about using the ExtractMailPrefix() function is available on the MS Azure documentation page.

    Azure AD IdP updating certificate

    After entering the login credentials on the MS Azure AD login page, a Sign On Error! may be displayed after being redirected to the Blackboard Learn GUI.

    With the following exception in the bb-services log:

    2016-10-13 12:03:23 +0800 — unsuccessfulAuthentication — org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
     at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:100)
     at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
     at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
     at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
     at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
     at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
     at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
     at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
     at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
     at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
     at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
     at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
     at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
     at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
     at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
     at sun.reflect.GeneratedMethodAccessor854.invoke(Unknown Source)
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
     at java.lang.reflect.Method.invoke(Method.java:498)
     at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:282)
     at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:279)
     at java.security.AccessController.doPrivileged(Native Method)
     at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
     at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:314)
     at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:253)
     at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:190)
     at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:46)
     at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:148)
     at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:144)
     at java.security.AccessController.doPrivileged(Native Method)
     at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:143)
     at blackboard.auth.provider.saml.customization.filter.BbSAMLExceptionHandleFilter.doFilterInternal(BbSAMLExceptionHandleFilter.java:30)
     [SNIP]
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
     at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
     at java.lang.Thread.run(Thread.java:745)
    Caused by: org.opensaml.common.SAMLException: Response doesn’t have any valid assertion which would pass subject validation
     at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:229)
     at blackboard.auth.provider.saml.customization.consumer.BbSAMLWebSSOProfileConsumerImpl.processAuthenticationResponse(BbSAMLWebSSOProfileConsumerImpl.java:40)
     at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87)
     … 230 more
    Caused by: org.opensaml.xml.validation.ValidationException: Signature is not trusted or invalid
     at org.springframework.security.saml.websso.AbstractProfileBase.verifySignature(AbstractProfileBase.java:272)
     at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAssertionSignature(WebSSOProfileConsumerImpl.java:419)
     at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAssertion(WebSSOProfileConsumerImpl.java:292)
     at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:214)
     … 232 more

    This is caused by the MS Azure AD IdP updating the certificate, but the metadata XML used by the Blackboard Learn SP not being adjusted to reflect the new certificate.

    Resolution

    • The new metadata XML file with the new certificate will need to be updated on the SAML Settings page in the Blackboard Learn GUI for the authentication provider.
    • The SAML B2 and the authentication provider will then need to be toggled Inactive/Available, while having the SAML authentication provider in ‘Active’ status, to have the updated metadata with the new certificate applied.
    • If a Blackboard Learn site has multiple authentication providers that share the same underlying certificate for the same underlying IdP Entity ID, ALL those authentication providers will need to be updated.

    Microsoft has indicated that that they will be updating certificates every 6 weeks from now on, and that such updates will be unannounced.

    IdP-initiated single sign on

    If a user first logs into their user portal and then selects the app for their Blackboard Learn site, a new browser tab opens to display a message: The specified resource was not found, or you do not have permission to access it.

    With the corresponding SAML related events in the stdout-stderr.log:

    INFO   | jvm 1    | 2016/08/16 10:49:22 | — /saml/SSO at position 1 of 10 in additional filter chain; firing Filter: ‘SecurityContextPersistenceFilter’
    INFO   | jvm 1    | 2016/08/16 10:49:22 | — HttpSession returned null object for SPRING_SECURITY_CONTEXT
    INFO   | jvm 1    | 2016/08/16 10:49:22 | — No SecurityContext was available from the HttpSession: [email protected] A new one will be created.
    INFO   | jvm 1    | 2016/08/16 10:49:22 | — /saml/SSO at position 2 of 10 in additional filter chain; firing Filter: ‘WebAsyncManagerIntegrationFilter’
    INFO   | jvm 1    | 2016/08/16 10:49:22 | — /saml/SSO at position 3 of 10 in additional filter chain; firing Filter: ‘HeaderWriterFilter’
    INFO   | jvm 1    | 2016/08/16 10:49:22 | — /saml/SSO at position 4 of 10 in additional filter chain; firing Filter: ‘FilterChainProxy’
    INFO   | jvm 1    | 2016/08/16 10:49:22 | — Checking match of request : ‘/saml/sso’; against ‘/saml/login/**’
    INFO   | jvm 1    | 2016/08/16 10:49:22 | — Checking match of request : ‘/saml/sso’; against ‘/saml/logout/**’
    INFO   | jvm 1    | 2016/08/16 10:49:22 | — Checking match of request : ‘/saml/sso’; against ‘/saml/bbsamllogout/**’
    INFO   | jvm 1    | 2016/08/16 10:49:22 | — Checking match of request : ‘/saml/sso’; against ‘/saml/sso/**’
    INFO   | jvm 1    | 2016/08/16 10:49:22 | — /saml/SSO at position 1 of 1 in additional filter chain; firing Filter: ‘SAMLProcessingFilter’
    INFO   | jvm 1    | 2016/08/16 10:49:22 | — Forwarding to /
    INFO   | jvm 1    | 2016/08/16 10:49:22 | — DispatcherServlet with name ‘saml’ processing POST request for [/auth-saml/saml/SSO]
    INFO   | jvm 1    | 2016/08/16 10:49:22 | — No mapping found for HTTP request with URI [/auth-saml/saml/SSO] in DispatcherServlet with name ‘saml’
    INFO   | jvm 1    | 2016/08/16 10:49:22 | — SecurityContext is empty or contents are anonymous — context will not be stored in HttpSession.
    INFO   | jvm 1    | 2016/08/16 10:49:22 | — Successfully completed request
    INFO   | jvm 1    | 2016/08/16 10:49:22 | — Skip invoking on
    INFO   | jvm 1    | 2016/08/16 10:49:22 | — SecurityContextHolder now cleared, as request processing completed

    The Service Provider Settings section of the SAML Authentication Settings page has changed and the Enable automatic SSO option should be checked to allow a user to access Blackboard Learn from their portal. If it is enabled, the ACS URL will also be changed to include an alias.

    Wrong document error

    After entering the login credentials on the SAML authentication provider login page, a Sign On Error! may be displayed after being redirected to the Blackboard Learn GUI.

    With the following DOMException and WRONG_DOCUMENT_ERR in the bb-services log:

    2016-11-18 12:27:31 -0600 — WRONG_DOCUMENT_ERR: A node is used in a different document than the one that created it.<P><span class=»captionText»>For reference, the Error ID is 86ebb81d-d3a3-4da5-95ab-1c94505f4281.</span> — org.w3c.dom.DOMException: WRONG_DOCUMENT_ERR: A node is used in a different document than the one that created it.
        at org.apache.xerces.dom.ParentNode.internalInsertBefore(Unknown Source)
        at org.apache.xerces.dom.ParentNode.insertBefore(Unknown Source)
        at org.apache.xerces.dom.NodeImpl.appendChild(Unknown Source)
        at org.opensaml.xml.encryption.Decrypter.parseInputStream(Decrypter.java:832)
        at org.opensaml.xml.encryption.Decrypter.decryptDataToDOM(Decrypter.java:610)
        at org.opensaml.xml.encryption.Decrypter.decryptUsingResolvedEncryptedKey(Decrypter.java:795)
        at org.opensaml.xml.encryption.Decrypter.decryptDataToDOM(Decrypter.java:535)
        at org.opensaml.xml.encryption.Decrypter.decryptDataToList(Decrypter.java:453)
        at org.opensaml.xml.encryption.Decrypter.decryptData(Decrypter.java:414)
        at org.opensaml.saml2.encryption.Decrypter.decryptData(Decrypter.java:141)
        at org.opensaml.saml2.encryption.Decrypter.decrypt(Decrypter.java:69)
        at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:199)
        at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:82)
        at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
        at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
        at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
        at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
        at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
        at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
        at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
        at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
        at sun.reflect.GeneratedMethodAccessor1209.invoke(Unknown Source)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:277)
        at org.apache.catalina.security.SecurityUtil$1.run(SecurityUtil.java:274)
        at java.security.AccessController.doPrivileged(Native Method)
        at javax.security.auth.Subject.doAsPrivileged(Subject.java:549)
        at org.apache.catalina.security.SecurityUtil.execute(SecurityUtil.java:309)
        at org.apache.catalina.security.SecurityUtil.doAsPrivilege(SecurityUtil.java:249)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237)
        at org.apache.catalina.core.ApplicationFilterChain.access$000(ApplicationFilterChain.java:55)
        at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:191)
        at org.apache.catalina.core.ApplicationFilterChain$1.run(ApplicationFilterChain.java:187)
        at java.security.AccessController.doPrivileged(Native Method)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:186)
        at blackboard.platform.servlet.DevNonceFilter.doFilter(DevNonceFilter.java:68)
        [SNIP]

    The reason the problem occurs is another B2/Project changed the system property javax.xml.parsers.DocumentBuilderFactory value from org.apache.xerces.jaxp.DocumentBuilderFactoryImpl to com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl.

    Temporary resolution

    Until a fix is released, the temporary resolution options are:

    1. Restart Bb services on each node.
    2. Turn off SAML response encryption on the IdP side. As the whole communication is over SSL, this will not reduce the security of the authentication.

    No option to add SAML to Provider Order

    When configuring SAML authentication, an institution may notice there is not an option to add a SAML authentication provider in the Provider Order section in Blackboard Learn GUI when navigating to System Admin > Building Blocks: Authentication > Provider Order.

    The reason there is not an option to add a SAML authentication provider to the Provider Order is that redirect type providers such as CAS and SAML hand off authentication to the remote authentication source. Those are not listed in the Provider Order as they are considered the authoritative source for authentication and handle their own authentication failures.

    Test SAML connection

    Beginning with the Q4 2016 release of Blackboard Learn, there is now an option to test the connection for a SAML provider in the Authentication section in the Blackboard Learn GUI. The connection test will check the following items:

    • Parse IdP metadata
    • Connect to IdP
    • Receive SAML response
    • Parse SAML response
    • Remote User ID match
    • Log in to Blackboard Learn

    To test the connection for a SAML authentication provider:

    1. Login to Blackboard Learn as an administrator.
    2. Navigate to System Admin > Building Blocks: Authentication > «SAML Provider Name» > Test Connection.
    3. Enter the IdP login credentials if prompted.

    The Test Connection feature can be used in lieu of manually enabling SAML debug logging in Blackboard Learn for multiple reasons.

    The Identity Provider Entity ID value that is displayed on the Test Connection output page is pulled from the Issuer element in the SAML POST from the IdP to Blackboard Learn after the user has been authenticated:

    <Issuer xmlns=»urn:oasis:names:tc:SAML:2.0:assertion»>http://bbpdcsi-adfs1.bbpdcsi.local/a…services/trust</Issuer>

    The SAML Attribute values displayed on the Test Connection output page in the SAML Response section are pulled from the Subject and AttributeStatement elements in the SAML POST from the IdP to Blackboard Learn after the user has been authenticated:

    <Subject>
        <NameID Format=»urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress»>luke.skywalker</NameID>
        [SNIP]
    </Subject>
    <AttributeStatement>
        <Attribute Name=»SamAccountName»>
            <AttributeValue>luke.skywalker</AttributeValue>
        </Attribute>
        <Attribute Name=»urn:oid:2.5.4.42″>
            <AttributeValue>Luke</AttributeValue>
        </Attribute>
        <Attribute Name=»urn:oid:2.5.4.4″>
            <AttributeValue>Skywalker</AttributeValue>
        </Attribute>
    </AttributeStatement>

    Debug logging

    If the attributes being released from the IdP and sent to Blackboard Learn during the authentication process are encrypted in the SAML response, the Firefox browser SAML tracer Add-on or Chrome SAML Message Decoder can’t be used to view those attributes. However, viewing the attributes and additional SAML related events in a log on the Blackboard Learn side can be accomplished by temporarily enabling debug logging inside the SAML 2.0 B2. Also, if a site has Blackboard Learn Q4 2016 or higher, the Test Connection feature can be used in lieu of manually enabling SAML debug logging in Blackboard Learn.

    To temporarily enable debug logging for the SAML 2.0 B2:

    1. Open the /usr/local/blackboard/content/vi/BBLEARN/plugins/bb-auth-provider-saml/webapp/WEB-INF/classes/log4j.properties

      log4j.rootCategory=DEBUG, CONSOLE

       
      # CONSOLE is set to be a ConsoleAppender using a PatternLayout.
      log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
      log4j.appender.CONSOLE.Threshold=DEBUG
      log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
      log4j.appender.CONSOLE.layout.ConversionPattern=- %m%n

       
      # Logging of Spring Security extension
      log4j.logger.org.springframework.security.saml=INFO

       
      # Logging of SAML messages, set to FINEST to enable
      log4j.logger.PROTOCOL_MESSAGE=FINEST

       
      # Logging of OpenSAML library
      log4j.logger.org.opensaml=INFO

      1. on line 1, change the log4j.rootCategory= from INFO to DEBUG
      2. on line 5, change the log4j.appender.CONSOLE.Threshold= from INFO to DEBUG
      3. on line 13, change the log4j.logger.PROTOCOL_MESSAGE= from INFO to FINEST
    2. Then have Bb services restarted with a rolling pushconfig being done so the new debug logging settings for the B2 are recognized by Blackboard Learn.
    3. Once the SAML 2.0 B2 is set to use debug, perform a test SAML authentication login as normal. This will get a dump of the SAML response sent back from the client’s IdP. The event is captured in the Tomcat stdout-stderr log and can be found by searching for AttributeValue or Attribute Name.

    Example:

    INFO   | jvm 1    | 2016/05/20 04:54:27 | — <saml2:Assertion xmlns:saml2=»urn:oasis:names:tc:SAML:2.0:assertion» ID=»_50725d4fa80d0d5689bd3ca9ac43b97c» IssueInstant=»2016-05-20T08:54:26.793Z» Version=»2.0″><saml2:Issuer>https://accounts.google.com/o/saml2?idpid=C00j2kl1x</saml2:Issuer><saml2:Subject><saml2:NameID Format=»urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified»>[email protected]</saml2:NameID><saml2:SubjectConfirmation Method=»urn:oasis:names:tc:SAML:2.0:cm:bearer»><saml2:SubjectConfirmationData InResponseTo=»a32977i74g7e88c731df1915ibj0iec» NotOnOrAfter=»2016-05-20T08:59:26.793Z» Recipient=»https://mhtest3.blackboard.com/auth-saml/saml/SSO»></saml2:SubjectConfirmationData></saml2:SubjectConfirmation></saml2:Subject><saml2:Conditions NotBefore=»2016-05-20T08:49:26.793Z» NotOnOrAfter=»2016-05-20T08:59:26.793Z»><saml2:AudienceRestriction><saml2:Audience>https://mhtest3.blackboard.com/shibboleth</saml2:Audience></saml2:AudienceRestriction></saml2:Conditions><saml2:AttributeStatement><saml2:Attribute Name=»urn:oid:1.3.6.1.4.1.5923.1.1.1.6″><saml2:AttributeValue xmlns:xsi=»http://www.w3.org/2001/XMLSchema-instance» xsi:type=»xs:anyType»>[email protected]</saml2:AttributeValue></saml2:Attribute><saml2:Attribute Name=»urn:oid:2.5.4.42″><saml2:AttributeValue xmlns:xsi=»http://www.w3.org/2001/XMLSchema-instance» xsi:type=»xs:anyType»>Bb</saml2:AttributeValue></saml2:Attribute><saml2:Attribute Name=»urn:oid:2.5.4.4″><saml2:AttributeValue xmlns:xsi=»http://www.w3.org/2001/XMLSchema-instance» xsi:type=»xs:anyType»>User_SAML2</saml2:AttributeValue></saml2:Attribute><saml2:Attribute Name=»urn:oid:0.9.2342.19200300.100.1.3″><saml2:AttributeValue xmlns:xsi=»http://www.w3.org/2001/XMLSchema-instance» xsi:type=»xs:anyType»>[email protected]</saml2:AttributeValue></saml2:Attribute></saml2:AttributeStatement><saml2:AuthnStatement AuthnInstant=»2016-05-20T08:54:26.000Z» SessionIndex=»_50725d4fa80d0d5689bd3ca9ac43b97c»><saml2:AuthnContext><saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml2:AuthnContextClassRef></saml2:AuthnContext></saml2:AuthnStatement></saml2:Assertion>
    INFO   | jvm 1    | 2016/05/20 04:54:27 | — Verification successful for URI «#_50725d4fa80d0d5689bd3ca9ac43b97c»
    INFO   | jvm 1    | 2016/05/20 04:54:27 | — The Reference has Type
    INFO   | jvm 1    | 2016/05/20 04:54:27 | — Redirecting to DefaultSavedRequest Url: https://mhtest3.blackboard.com/webap…ute/defaultTab
    INFO   | jvm 1    | 2016/05/20 04:54:27 | — Redirecting to ‘https://mhtest3.blackboard.com/webap…ute/defaultTab’
    INFO   | jvm 1    | 2016/05/20 04:54:27 | — SecurityContext ‘[email protected]e17344: Authentication: org.springf[email protected]63e17344: Principal: [email protected]; Credentials: [PROTECTED]; Authenticated: true; Details: [email protected]71c59d; Not granted any authorities’ stored to HttpSession: ‘[email protected]
    INFO   | jvm 1    | 2016/05/20 04:54:27 | — SecurityContextHolder now cleared, as request processing completed

    Using the above example, that whole embedded saml2:Assertion document (from <saml2:Assertion opening XML element to </saml2:Assertion> closing XML element) that contains the attributes can also be selected using a method of choice to format it in a human readable way.

    Option 1

    1. Copy the whole embedded saml2:Assertion document (from <saml2:Assertion opening XML element to </saml2:Assertion> closing XML element).
    2. Open a web browser, go to the Onelogin SAML Developer Tools page and select the XML Pretty Print tool.
    3. Paste the copied saml2:Assertion into the XML window and select Turn Pretty.

    Option 2

    1. Select the whole embedded saml2:Assertion document (from <saml2:Assertion opening XML element to </saml2:Assertion> closing XML element)
    2. Save that into a new file somewhere; either on the server or on a local workstation. If saving on a local workstation copy that file to a Linux server and save in /tmp/incoming_response.xml.
    3. Run xmllint on the file so that it can be formatted it in a human readable way.

      # xmllint —format /tmp/incoming_response.xml > /tmp/formatted_response.xml

    4. Open the /tmp/formatted_response.xml and observe the attributes can be easily viewed line by line:

      <?xml version=»1.0″?>
      <saml2:Assertion xmlns:saml2=»urn:oasis:names:tc:SAML:2.0:assertion» ID=»_50725d4fa80d0d5689bd3ca9ac43b97c» IssueInstant=»2016-05-20T08:54:26.793Z» Version=»2.0″>
        <saml2:Issuer>https://accounts.google.com/o/saml2?idpid=C00j2kl1x</saml2:Issuer>
        <saml2:Subject>
          <saml2:NameID Format=»urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified»>[email protected]</saml2:NameID>
          <saml2:SubjectConfirmation Method=»urn:oasis:names:tc:SAML:2.0:cm:bearer»>
            <saml2:SubjectConfirmationData InResponseTo=»a32977i74g7e88c731df1915ibj0iec» NotOnOrAfter=»2016-05-20T08:59:26.793Z» Recipient=»https://mhtest3.blackboard.com/auth-saml/saml/SSO»/>
          </saml2:SubjectConfirmation>
        </saml2:Subject>
        <saml2:Conditions NotBefore=»2016-05-20T08:49:26.793Z» NotOnOrAfter=»2016-05-20T08:59:26.793Z»>
          <saml2:AudienceRestriction>
            <saml2:Audience>https://mhtest3.blackboard.com/shibboleth</saml2:Audience>
          </saml2:AudienceRestriction>
        </saml2:Conditions>
        <saml2:AttributeStatement>
          <saml2:Attribute Name=»urn:oid:1.3.6.1.4.1.5923.1.1.1.6″>
            <saml2:AttributeValue xmlns:xsi=»http://www.w3.org/2001/XMLSchema-instance» xsi:type=»xs:anyType»>[email protected]</saml2:AttributeValue>
          </saml2:Attribute>
          <saml2:Attribute Name=»urn:oid:2.5.4.42″>
            <saml2:AttributeValue xmlns:xsi=»http://www.w3.org/2001/XMLSchema-instance» xsi:type=»xs:anyType»>Bb</saml2:AttributeValue>
          </saml2:Attribute>
          <saml2:Attribute Name=»urn:oid:2.5.4.4″>
            <saml2:AttributeValue xmlns:xsi=»http://www.w3.org/2001/XMLSchema-instance» xsi:type=»xs:anyType»>User_SAML2</saml2:AttributeValue>
          </saml2:Attribute>
          <saml2:Attribute Name=»urn:oid:0.9.2342.19200300.100.1.3″>
            <saml2:AttributeValue xmlns:xsi=»http://www.w3.org/2001/XMLSchema-instance» xsi:type=»xs:anyType»>[email protected]</saml2:AttributeValue>
          </saml2:Attribute>
        </saml2:AttributeStatement>
        <saml2:AuthnStatement AuthnInstant=»2016-05-20T08:54:26.000Z» SessionIndex=»_50725d4fa80d0d5689bd3ca9ac43b97c»>
          <saml2:AuthnContext>
            <saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</saml2:AuthnContextClassRef>
          </saml2:AuthnContext>
        </saml2:AuthnStatement>
      </saml2:Assertion>

    Create a SAML authentication provider and IdP for testing

    Use the steps below to create an Identity Provider (IdP) using Centrify’s free SSO authentication solution.

    That IdP can then be configured as the SAML authentication provider in a Blackboard Learn Service Provider (SP):

    Blackboard Learn Service Provider

    1. Login to the Blackboard Learn GUI as an administrator and navigate to System Admin > Authentication.
    2. Select Create Provider > SAML.
    3. Input the following settings:
      • Name > SAML or anything you want.
      • Authentication Provider > Inactive (for now).
      • User Lookup Method > Username
      • Restrict by Hostname > Use this provider for any hostnames
      • Link Text > SAML Centrify Login
    4. Select Save and Configure.
    5. In the Entity ID field, set this to anything you want (but if you change it you must provide the updated Service Provider Metadata to the Identity Provider). Simply copy/paste the ACS URL.
    6. Under Service Provider Metadata, select Generate and save the file to your desktop.
    7. Under Data Source, it is recommended to create a new Data Source for this named CENTRIFY, otherwise use SYSTEM or whatever you choose
    8. Next to Enable JIT Provisioning, check this box so that an account is automatically created when attempting to login via this SAML authentication provider if the user does not exist. If JIT Provisioning is not selected, the user in Blackboard Learn will need to be created manually.
    9. In the Compatible Data Sources list, be sure to select the data sources that this authentication provider should be compatible with.
    10. Select Point Identity Provider for the Identity Provider Type.
    11. Skip the Identity Provider Metadata for now, you will upload the file after it has been created in the Centrify IdP section.
    12. For the Map SAML Attributes section, use NameID for the Remote User ID.
    13. Select Submit.

    Centrify Identity Provider

    1. Go to https://www.centrify.com/express/identity-service and select Start Now in the Express column at the bottom of the page.
    2. Enter your info to sign up and select Start Now.
    3. A welcome email is then sent with your admin credentials, use that to login to: https://cloud.centrify.com.
    4. Select Skip on the Welcome to Centrify Identify Service window.
    5. In the Apps tab at the top of the page, select the Add Web Apps button.
    6. In the Custom tab, scroll down and select the Add button for SAML. Select Yes.
    7. Select Close at the bottom of the Add Web Apps window.
    8. Go to the Apps tab. In the Application Settings section, select the Upload SP Metadata button and upload the file that was created in Step 6 of the Blackboard Learn SP section.
    9. The Assertion Consumer Service URL should automatically populate after uploading the SP Metadata.
    10. Uncheck Encrypt Assertion. This allows the attributes being released from the IdP and sent to Blackboard Learn to be viewed using the Firefox browser SAML tracer Add-on or Chrome SAML Message Decoder.

      As the whole communication is over SSL this will not reduce the security of the authentication

    11. Scroll down and select Download Identity Provider SAML Metadata. Save the file to your desktop.
    12. Select Save and go to the next section.
    13. Enter a name for the Description section. Select Save and go to the next section.
    14. In the User Access section, select Everybody and System Administrator. Select Save.
    15. Do not make any selections in the Policy section.
    16. For the Account Mapping section, confirm that userprincipalname is entered for the Directory Service field name.
    17. For the Advanced section, add the following line to the bottom of the script used to generate a SAML assertion for the application:

      The complete script will be:

      setIssuer(Issuer);
      setSubjectName(UserIdentifier);
      setAudience(‘https://YourLearnServer.blackboard.c…saml/saml/SSO’);
      setRecipient(ServiceUrl);
      setHttpDestination(ServiceUrl);
      setSignatureType(‘Assertion’);
      setNameFormat(’emailaddress’);
      setAttribute(«NameID», LoginUser.Get(«userprincipalname»));

      Which will allow the Centrify IdP to release an AttributeStatement with the User ID in the SAML POST.

      Example:

      <AttributeStatement>
          <Attribute Name=»NameID»
                     NameFormat=»urn:oasis:names:tc:SAML:2.0:attrname-format:basic»
                     >
              <AttributeValue>[email protected]</AttributeValue>
          </Attribute>
      </AttributeStatement>

      More on specifying assertion elements in the Centrify SAML script

    18. Select Save.
    19. No changes should need to be made to the remaining sections (App Gateway, Changelog and Workflow).
    20. In the Apps tab, confirm the SAML app was automatically deployed.
    21. In the Users tab, select Add Users, enter the account info for a user, and select Create User.
    22. Log back into the Blackboard Learn GUI as an administrator, navigate to System Admin > Authentication > SAML Authentication Provider Name > SAML Settings > Identity Provider Settings, upload the IdP Metadata file that was saved to your desktop in Step 13 and select Submit.

    The Centrify IdP user that was created can now login to Blackboard Learn via SAML by selecting that authentication provider on the login page, and logout of Blackboard Learn using the extra End SSO Session logout button on the End all sessions? page that is displayed after selecting the logout button at the top right of Blackboard Learn.

    Configuration details in Blackboard Learn database

    IdP Metadata

    If for some reason the original IdP metadata XML file that was uploaded in the Blackboard Learn GUI on the SAML Authentication Settings page is no longer available locally, the contents of that file can be viewed in the Blackboard Learn database. The IdP metadata XML file contents are stored in the extended_data field as a blob data type in the auth_provider table.

    Oracle

    With the Oracle database used for Enterprise Blackboard Learn systems running Red Hat Linux, since blob is the data type for the extended_data field, the BLOB2CLOB stored procedure should be used in order to view the data:

    SELECT  blob2clob(extended_data)
    FROM    auth_provider
    WHERE   name = ‘<Authentication Provider Name>’

    Certificate and key

    The SAML B2 certificate and key values are stored in the Blackboard Learn database in the system_registry table in the registry_key column. They can be viewed with the following query:

    SELECT  pk1, dtmodified, registry_key, registry_long_value
    FROM    system_registry
    WHERE   upper(registry_key) LIKE upper(‘%saml%’)

    Change text on End SSO Session logout page

    An institution may inquire if it is possible to change the text on the End SSO Session logout page. It is possible to change the text on the End SSO Session logout page by editing the Language Pack:

    1. Open the Language Pack file.
    2. Navigate to auth-provider-saml/src/main/webapp/WEB-INF/bundles/bb-manifest-en_US.properties.
    3. Update the Message Keys:

      saml.single.logout.warning.conent.description // the first line
      saml.single.logout.warning.conent.recommend // second line
      saml.single.logout.warning.endsso.title // third line
      saml.single.logout.warning.endsso.button // the button
      saml.single.logout.warning.backtolearn // the cancel button

    Redirect users to the IdP login page

    The standard Blackboard Learn login page presents username and password fields for the default Learn Internal authentication provider. When you enable SAML authentication, a small «Sign in using…» link for SAML appears at the bottom of this page, so you may want to redirect users to the IdP’s authentication server automatically when they access the Learn login page.

    One option to accomplish this is to navigate to System Admin > Authentication and set the default Learn Internal authentication to Inactive, which means a login page is no longer displayed, and immediately the user is redirected to the SAML login. The problem with that option is that it overrides the default login URL and prevents any non-SAML user to login.

    To avoid this issue and provide almost the same result, use a Custom Login Page. Users are redirected to the SAML authentication provider’s IdP login page, but the default login link is also usable.

    1. Ensure the default Learn Internal authentication is active
    2. On the default login page, copy the location of the provider redirect e.g. Sign in using… SAML. Right-click on the link and select Copy Link Location.
    3. Navigate to System Admin > Communities > Brands and Themes > Customize Login Page.
    4. Select Download next to Default Login Page to download the default login JSP file.
    5. Open the JSP file with a text editor. Add the following sample HTML to the login JSP file and replace the URL text with the URL that was copied in Step 2.

      <!DOCTYPE HTML PUBLIC «-//W3C//DTD HTML 4.0 Transitional//EN»>
      <html>
      <head>
      <title>Blackboard Learn — Redirect</title>
      <meta http-equiv=»REFRESH» content=»0;url=https://URL_Goes_Here»></HEAD>
      <BODY style=»font-family: arial,sans-serif;font-size: small; color: grey; padding: 1em; «>
      Redirecting… <a style=»color:grey» href=»https://URL_Goes_Here»>Go to login page</a> if you are not automatically redirected.
      </BODY>
      </HTML>

    6. Navigate to Customize Login Page in Learn once more. Select Use Custom Page and then upload the updated login JSP file.
    7. After making the changes, select Preview on the Customize Login Page to confirm the redirect is working properly.

    Users going to the main URL will now be redirected to the login page for the SAML authentication provider. Administrators can still log in using the Learn internal authentication via the default login page: /webapps/login/?action=default_login or/webapps/login/login.jsp.

    More on customizing the login page in the Ultra experience

  • Unable to rename delphi32 to delphi32 dro ошибка
  • Unable to read beyond the end of the stream раст ошибка
  • Unable to perform link c builder ошибка
  • Unable to lock the disk boot your computer from a linux based bootable media ошибка
  • Unable to lock the disk acronis ошибка