OAUTH2 básico - una pesadilla :-(

Hola chicos,

Llevo 2 días intentando configurar OAUTH2 y tengo problemas.

Configuré todo según la documentación, pero me sale esto todo el tiempo:

(oauth2_basic) ¡Error de autenticación! invalid_scope: OmniAuth::Strategies::OAuth2::CallbackError, invalid_scope | Alcance(s) desconocido(s)/inválido(s)
Iniciado GET "/auth/failure?message=invalid_scope&origin=<censored>%2Latest&strategy=oauth2_basic" para 10.153.107.106 en 2024-11-27 05:30:33 +0000
Procesando por Users::OmniauthCallbacksController#failure como HTML
  Parámetros: {"message"=>"invalid_scope", "origin"=>"<censored>/latest", "strategy"=>"oauth2_basic"}

Mi configuración en el panel (con respecto a los alcances) es la siguiente:

El IdP está configurado así:

¿Alguien tiene alguna pista sobre cómo depurar esto un poco más?

¿Curl útiles, con los que pueda probar, o mejor salida de depuración (ya activé la opción de depuración detallada)?

Me estoy volviendo loco con esto :frowning:

¡Gracias y saludos!

WS

ACTUALIZACIÓN:

Acabo de restablecer las opciones a solo “scope”

pero no funcionó :frowning:

2 Me gusta

notado que nuestro IdP tenía el ámbito incorrecto en su interfaz de usuario …

openId está en la interfaz de usuario
openid es el real :slight_smile:
un paso más, pero ahora estoy recibiendo un tiempo de espera agotado
image
después de esta llamada


OAuth2 Debugging: request POST https://<myAuthProvider/auth/oauth2/realms/root/realms/<realm>/access_token

Headers:
--- !ruby/hash-with-ivars:Faraday::Utils::Headers
ivars:
  :@names:
    user-agent: User-Agent
    content-type: Content-Type
elements:
  User-Agent: Faraday v2.12.1
  Content-Type: application/x-www-form-urlencoded


Body:
---
client_id: <client-id>
client_secret: <client-secret>
grant_type: authorization_code
code: <code
redirect_uri: https://<myDiscourse>/auth/oauth2_basic/callback

terminando en

Pero como la llamada de autorización que obtiene el código se realizó correctamente, no puede haber ningún problema de red, ¿verdad?

1 me gusta

Cuando emito la llamada con un curl

curl --request POST \
  --url https://<IdP address>/auth/oauth2/realms/root/realms/<realm>/access_token \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data client_id=<clientId> \
  --data client_secret=<secret> \
  --data grant_type=authorization_code \
  --data code=<code > \
  --data redirect_uri=https://<discourse>/auth/oauth2_basic/callback

desde el contenedor de docker de discourse obtengo esto

{
  "access_token": "<token>",
  "refresh_token": "<refresh_token>",
  "scope": "openid profile email",
  "id_token": "<censored>",
  "token_type": "Bearer",
  "expires_in": 7199
}

¿Puede ser un problema por esto?

image

Estos campos no están en la respuesta :frowning:

2 Me gusta

¿nadie? :frowning:

1 me gusta

Estoy muy interesado en el tema porque estoy investigando la cantidad de esfuerzo que requeriría mi primera página de Discourse para mi vecindario y luego, gradualmente, para las escuelas de mis hijos. Estoy sobrecargado de notificaciones de todas las diferentes plataformas.
Reducir la fricción en la página es fundamental, así que me gustaría ofrecer algo de ayuda. Soy novato en Ruby, así que solo puedo ofrecer algunos recursos que encontré e ideas sobre los recursos.

Es posible que ya lo hayas mirado, pero quizás quieras consultar el repositorio en GitHub para discourse-openid-connect

El repositorio tiene 37 colaboradores y me imagino que uno de ellos podría ayudarte a responder tu pregunta.

Espero que esto ayude porque es una gran pregunta.

1 me gusta

Hey @thecatfix,

Parece prometedor. Lo probaré de inmediato y daré mi opinión lo antes posible.
Desafortunadamente, no tengo tiempo hoy. Quizás pueda trabajar en ello el fin de semana.

¡Muchas gracias y que tengas un buen fin de semana!

Hola,

No pude esperar y lo probé hoy, pero de alguna manera los chicos de nuestro departamento de EAM arruinaron este descubrimiento. No funciona y obtengo un cliente no válido - autenticación fallida a pesar de estar 1000% seguro de que las credenciales funcionan (probado con curls).
Así que estoy de vuelta al principio.

Lo interesante es que obtengo un timeoutError todo el tiempo para la solicitud al punto final de autorización, y llega bastante rápido.

Faraday::TimeoutError (Net::ReadTimeout with #<TCPSocket:(closed)>)

Encontré esto, y tengo curiosidad si algo así también es posible en discourse?

No soy un tipo de Ruby en absoluto, así que necesitaré ayuda.

Quiero depurar cada solicitud que se maneja en el lado de discourse. ¿Es eso posible?
También pensé en instalar un proxy local para interceptar las llamadas, pero antes de entrar en esto, quería preguntar si hay métodos más fáciles :slight_smile:

¿Quieres ver el tráfico HTTP sin procesar o poder entrar en el código?

El tráfico sin procesar…

solicitudes que se envían con encabezados y carga útil…

¿es eso posible de alguna manera?

La forma más fácil de hacerlo es desde dentro del contenedor; puedes interceptar e imprimir solicitudes entre nginx y Discourse entrando en el contenedor y ejecutando:

apt-get update && apt-get -y install scapy
scapy

# en el prompt de scapy, pega:
class Callback:
  def __init__(self):
    self.last = None
  def prn(self, p):
    if p != self.last: # los pcap en lo capturan dos veces
      self.last = p
      p.hide_defaults()
      print(repr(p)) # esta línea imprime el paquete, mantenla o déjala
      if scapy.packet.Raw in p.layers():
        try:
          print(p.load.decode())
        except:
          print(p.load)

sniff(filter="port 3000", iface="lo", prn=Callback().prn)
1 me gusta

Esto es genial, gracias… ¡estaba buscando exactamente una herramienta así!

Hmm… pero
parece que Discourse está recibiendo la devolución de llamada y luego…
Según mi entendimiento, debería contactar al endpoint de userinfo y obtener la información del usuario con el código recuperado, pero estoy recibiendo un HTTP 500.


GET /auth/oauth2_basic/callback?code=_B1HRB1e6kZKc8nuGLkzGC8&iss=https%3A%2F%2F%3CmyAuthDomain%3E%3A443%2Fauth%2Foauth2%2Frealms%2Froot%2Frealms%2Fintranetrealm&state=544801ae7e8262ea1667ea7531487f28e83aae232d5182b4&client_id=eadaa55a-1697-494a-8fg5-bb1137c68caa HTTP/1.0
Host: <discourseHost>
X-Request-Start: t=1732956951.485
X-Real-IP: 10.111.101.84
X-Forwarded-For: 10.131.101.84
X-Forwarded-Proto: https
Connection: close
cache-control: max-age=0
upgrade-insecure-requests: 1
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
sec-fetch-site: same-site
sec-fetch-mode: navigate
sec-fetch-user: ?1
sec-fetch-dest: document
sec-ch-ua: "Google Chrome";v="131", "Chromium";v="131", "Not_A Brand";v="24"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
referer: https://discourseHost/
accept-encoding: gzip, deflate, br, zstd
accept-language: de-DE,de;q=0.9
priority: u=0, i
cookie: lbwdn=01; win=teUNUPSc8oibB......

<Ether  dst=00:00:00:00:00:00 src=00:00:00:00:00:00 type=IPv4 |<IP  ihl=5 len=52 id=7742 flags=DF frag=0 ttl=127 proto=tcp chksum=0xdf83 src=127.0.0.1 dst=127.0.0.1 |<TCP  sport=3000 dport=33574 seq=271589520 ack=3955524768 dataofs=8 flags=A window=499 chksum=0xfe28 options=[('NOP', None), ('NOP', None), ('Timestamp', (3962821542, 3962821542))] |>
<Ether  dst=00:00:00:00:00:00 src=00:00:00:00:00:00 type=IPv4 |<IP  ihl=5 len=281 id=55898 flags=DF frag=0 ttl=127 proto=tcp chksum=0x2282 src=127.0.0.1 dst=127.0.0.1 |<TCP  sport=3000 dport=33530 seq=491394 ack=1852886175 dataofs=8 flags=PA window=507 chksum=0xff0d options=[('NOP', None), ('NOP', None), ('Timestamp', (3962823893, 3962816870))] |<Raw  load='HTTP/1.1 500 Internal Server Error\r\nDate: Sat, 30 Nov 2024 08:55:53 GMT\r\nConnection: close\r\nContent-Type: text/html; charset=utf-8\r\nContent-Length: 658\r\nX-Request-Id: 7f4bafa0-7590-4b9b-8b8d-70a4fa1ae6c5\r\nX-Runtime: 10.078459\r\n\r\n' |>>>
HTTP/1.1 500 Internal Server Error
Date: Sat, 30 Nov 2024 08:55:53 GMT
Connection: close
Content-Type: text/html; charset=utf-8
Content-Length: 658
X-Request-Id: 7f4bafa0-7590-4b9b-8b8d-70a4fa1ae6c5
X-Runtime: 10.078459

.....

<Ether  dst=00:00:00:00:00:00 src=00:00:00:00:00:00 type=IPv4 |<IP  ihl=5 len=52 id=15439 flags=DF frag=0 ttl=127 proto=tcp chksum=0xc172 src=127.0.0.1 dst=127.0.0.1 |<TCP  sport=33574 dport=3000 seq=3955524768 ack=271589749 dataofs=8 flags=A window=511 chksum=0xfe28 options=[('NOP', None), ('NOP', None), ('Timestamp', (3962831618, 3962831618))] |>
<Ether  dst=00:00:00:00:00:00 src=00:00:00:00:00:00 type=IPv4 |<IP  ihl=5 len=710 id=7744 flags=DF frag=0 ttl=127 proto=tcp chksum=0xdcef src=127.0.0.1 dst=127.0.0.1 |<TCP  sport=3000 dport=33574 seq=271589749 ack=3955524768 dataofs=8 flags=PA window=512 chksum=0xbb options=[('NOP', None), ('NOP', None), ('Timestamp', (3962831618, 3962831618))] |<Raw  load='<!DOCTYPE html>\n<html>\n<head>\n  <title>Oops - Error 500</title>\n  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">\n</head>\n<body>\n    <h1>Oops</h1>\n    <p>The software powering this discussion forum encountered an unexpected problem. We apologize for the inconvenience.</p>\n    <p>Detailed information about the error was logged, and an automatic notification generated. We\'ll take a look at it.</p>\n    <p>No further action is necessary. However, if the error condition persists, you can provide additional detail, including steps to reproduce the error, by posting a discussion topic in the site\'s feedback category.</p>\n</body>\n</html>\n' |>>>>
<!DOCTYPE html>
<html>
<head>
  <title>Oops - Error 500</title>
.....

En los logs imprime estas líneas

Una captura de pantalla que muestra un error de red con un tiempo de espera agotado, que incluye encabezados HTTP y detalles del error. (Subtitulado por IA)

Me parece que Discourse tiene problemas para manejar la devolución de llamada, y ahora necesitaría una visión más profunda de lo que sucede detrás de escena en Discourse.

No obtengo ninguna pista en los registros a pesar de haber activado todos los modos de depuración que conozco.

Hmmm, realmente estoy atascado con esto y es frustrante :frowning:

Hola a todos,

Ya estoy mucho más avanzado :slight_smile:

Tenía que ver con nuestra infraestructura EAM…

Ahora tengo el siguiente problema, sin embargo :smiley:

Mi userinfotoken se ve así:


{
  "company-i": "A1",
  "accounting-code": "5806",
  "given_name": "Mister",
  "family_name": "Bean",
  "name": "Mister Bean",
  "departmentnumber": "Covert Operations",
  "salutation": "Dude",
  "description": "Some description",
  "preferredlanguage": "DE",
  "inumber": "723jfio-7zwe8489",
  "employeenumber": "36484332",
  "employeetype": "BigCompany",
  "uid": "f57383",
  "adupn": "f57383@europe.bigcom.corp",
  "uniqueuid": "f57383",
  "uniqueuidq": "f57383",
  "loginname": "f57383",
  "email": "Mister.Bean@bigcom.corp",
  "sub": "f57383",
  "subname": "f57383"
}

Y estoy recibiendo este error en los logs:


ActiveRecord::NotNullViolation (PG::NotNullViolation: ERROR:  null value in column "provider_uid" of relation "user_associated_accounts" violates not-null constraint
DETAIL:  Failing row contains (6, oauth2_basic, null, null, 2024-12-03 13:06:49.831182, {"name": "Mister Bean", "email": "Mister.Bean@bigcom.corp", "user..., {"token": "dszghsdhsdfoph", "expires": true, "expir..., {}, 2024-12-03 13:06:49.831362, 2024-12-03 13:06:49.831362).

Parece que Discourse no puede mapear la respuesta del userinfoendpoint a sus nombres internos.

He intentado configurarlo a través de la interfaz de usuario:

pero probablemente lo hice mal.

¿Alguien podría darme una pista sobre cómo configurarlo?

Gracias y saludos,

WS

¿Está relleno oauth2 json user id path?

Asegúrate de que estos valores estén configurados: https://meta.discourse.org/t/configure-sign-up-and-log-in-with-auth0-using-the-oauth2-basic-plugin/64633#configure-discourse-3.

Hola,

Gracias por responder.

Parece que mi proveedor no envía los campos provider_name y provider_uid, y por lo tanto Discourse intenta crear la entrada sin ellos y obtiene una violación de NotNull.
Pero, ¿no es responsabilidad del plugin (oauth2_basic) rellenar estos valores (si no vienen del IdP remoto)?
Esperaría algo como

provider_name: “oauth2_basic”
provider_uid: “1234”

Usado automáticamente con cada inicio de sesión de usuario… :frowning:

El provider_name se fija en oauth2_basic y el provider_uid sería lo que sea que introduzcas en ruta del id de usuario json de oauth2.

Solo tienes que establecer esa configuración del sitio en la ruta del id según lo que devuelva tu proveedor. El plugin utiliza esta ruta json para rellenar el provider_uid, por lo que si actualmente está vacío o es una ruta que no existe, el valor será nil.

Por tu json anterior, parece que el valor debería ser sub.

2 Me gusta

Pero hice eso…

Tienes razón, la ruta debería ser “sub”, pero la configuré aquí

Espera… Tenías razón, y yo soy estúpido :frowning:

Configuración incorrecta…

¡Ahora funciona!

2 Me gusta

¿Hay alguna forma de guardar esta configuración en algún lugar? :smiley:
¿hacer una copia de seguridad solo de la configuración?

¿Están en la base de datos?

Eso es genial.

Toda la configuración del sitio se guarda en la base de datos. Suponiendo que tenga acceso a la consola de Rails, lo siguiente debería mostrarle una lista de la configuración.

SiteSetting.where("name LIKE 'oauth2_%'").pluck(:name, :value)

También puede simplemente crear una copia de seguridad.