Request failed with status code 401 à l’extérieur

Bonjour à tous,

Tout d’abord merci pour ce plugin qui permet de se faire une super interface sur mobile!

Je rencontre un probleme avec l’authentification via Websocket.

En effet, j’utilise Traefik couplé à Authelia pour la partie authentification web, je souhaiterais donc utiliser les websocket pour l’authentification de l’application.

Lorsque j’enrôle mon téléphone en local pas de soucis mais je n’accède plus aux données des que je suis à l’extérieur. J’ai donc testé l’enrôlement via une connexion 4G et j’ai le message d’erreur suivant: Request failed with status code 401

Le probleme semble donc venir de la connexion via le websocket pourtant j’ai bien redirigé le port 8090 de mon ip publique vers la machine Jeedom et j’ai régénéré le QR du téléphone puis relancer les services.Un petit telnet me confirme que le port 8090 est bien ouvert sur la Freebox.

Ma configuration est la suivante:

Jeedom Core : 4.2.20
Version JC : 1.3.1
DNS Jeedom : non

Equipements :
  archos : v1.3.0 sur android [os : 27] (ws)
  tel_clark : v1.3.0 sur android [os : 29] (ws)
  tel_rv : v1.3.0 sur android [os : 29] (ws)
  tel_shannon : non enregistré
  tel_so : v1.3.0 sur android [os : 29] (ws)

J’ai activé le debug pour les logs mais je ne vois rien qui me choque.

Merci par avance.

Salut

Pcq le probleme est avant d arriver au plugin, donc pas de log.

Mauvaise redirection, mauvaise info sur la page configuration du plugin, certificat pas a jour ou qui ne correspond pas au dns utilisés, etc…

Bonjour tomitomas,

Merci pour ta réponse mais j’avoue ne pas voir de d’ou pourrait provenir le souci, peut être comme tu le dis des certificats qui sont générés sur le proxy Traefik et qui ne sont pas stockés sur la machine Jeedom ?

Pour info,j’ai un peu plus de logs coté client (téléphone mobile en cours d’enrolement):

13:43:28 | ERROR | Error in sendToJcApi {"message":"Request failed with status code 401","name":"AxiosError","config":{"transitional":{"silentJSONParsing":true,"forcedJSONParsing":true,"clarifyTimeoutError":false},"transformRequest":[null],"transformResponse":[null],"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1,"maxBodyLength":-1,"env":{"FormData":null},"headers":{"Accept":"application/json, text/plain, */*","Content-Type":"application/json"},"cancelToken":{"promise":{"_h":1,"_i":0,"_j":null,"_k":{"onRejected":null,"promise":{"_h":0,"_i":0,"_j":null,"_k":null}}},"_listeners":[]},"method":"post","url":"https://xxx.xxx.xxxx.org/plugins/JeedomConnect/core/api/JeedomConnect.api.php","data":"{\"method\":\"CHECK_USER\",\"params\":{\"userHash\":\"u0akyjfsH8GVaUfmBvZxQYfp8g1a6BIj\",\"apiKey\":null},\"jsonrpc\":\"2.0\",\"id\":xxxxxx}"},"code":"ERR_BAD_REQUEST","status":401}
13:43:28 | ERROR | CHECK_USER error {"message":"Request failed with status code 401","name":"AxiosError","config":{"transitional":{"silentJSONParsing":true,"forcedJSONParsing":true,"clarifyTimeoutError":false},"transformRequest":[null],"transformResponse":[null],"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1,"maxBodyLength":-1,"env":{"FormData":null},"headers":{"Accept":"application/json, text/plain, */*","Content-Type":"application/json"},"cancelToken":{"promise":{"_h":1,"_i":0,"_j":null,"_k":{"onRejected":null,"promise":{"_h":0,"_i":0,"_j":null,"_k":null}}},"_listeners":[]},"method":"post","url":"https://xx.xx.org/plugins/JeedomConnect/core/api/JeedomConnect.api.php","data":"{\"method\":\"CHECK_USER\",\"params\":{\"userHash\":\"xxxxxxxx\",\"apiKey\":null},\"jsonrpc\":\"2.0\",\"id\":xxxxxxxxxx}"},"code":"ERR_BAD_REQUEST","status":401}
13:45:51 | INFO | App state changed to background
13:46:15 | INFO | App state changed to active
13:46:15 | DEBUG | [main] set secure session to false 24473
13:46:54 | DEBUG | net settings : {"details":{"isConnectionExpensive":true,"carrier":"","cellularGeneration":"4g"},"isConnected":true,"type":"cellular","isInternetReachable":false,"isWifiEnabled":false}
13:46:55 | DEBUG | net settings : {"details":{"isConnectionExpensive":false,"frequency":5180,"strength":74,"bssid":"02:00:00:00:00:00"},"isConnected":true,"type":"wifi","isInternetReachable":false,"isWifiEnabled":true}
13:46:55 | DEBUG | sendToJcApi  {"url":"http://192.168.xx.xx/plugins/JeedomConnect/core/api/JeedomConnect.api.php","data":{"method":"PING","jsonrpc":"2.0","id":xxxxxxx,"params":{"apiKey":null}},"baseUrl":"http://192.168.xx.xx"}
13:46:55 | DEBUG | net settings : {"details":{"isConnectionExpensive":false,"frequency":5180,"strength":74,"bssid":"02:00:00:00:00:00"},"isConnected":true,"type":"wifi","isInternetReachable":true,"isWifiEnabled":true}
13:46:55 | DEBUG | sendToJcApi  {"url":"http://192.168.xx.xx/plugins/JeedomConnect/core/api/JeedomConnect.api.php","data":{"method":"PING","jsonrpc":"2.0","id":xxxxxxx,"params":{"apiKey":null}},"baseUrl":"http://192.168.xx.xx"}
13:46:55 | DEBUG | net settings : {"details":{"isConnectionExpensive":false,"frequency":5180,"strength":74,"bssid":"02:00:00:00:00:00"},"isConnected":true,"type":"wifi","isInternetReachable":true,"isWifiEnabled":true}
13:46:55 | DEBUG | sendToJcApi  {"url":"http://192.168.xx.xx/plugins/JeedomConnect/core/api/JeedomConnect.api.php","data":{"method":"PING","jsonrpc":"2.0","id":xxxxxxxxx,"params":{"apiKey":null}},"baseUrl":"http://192.168.xx.xx"}
13:46:55 | ERROR | Error in sendToJcApi {"message":"Network Error","name":"AxiosError","config":{"transitional":{"silentJSONParsing":true,"forcedJSONParsing":true,"clarifyTimeoutError":false},"transformRequest":[null],"transformResponse":[null],"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1,"maxBodyLength":-1,"env":{"FormData":null},"headers":{"Accept":"application/json, text/plain, */*","Content-Type":"application/json"},"cancelToken":{"promise":{"_h":1,"_i":0,"_j":null,"_k":{"onRejected":null,"promise":{"_h":0,"_i":0,"_j":null,"_k":null}}},"_listeners":[null]},"method":"post","url":"http://192.168.xx.xx/plugins/JeedomConnect/core/api/JeedomConnect.api.php","data":"{\"method\":\"PING\",\"jsonrpc\":\"2.0\",\"id\":xxxxxxxx,\"params\":{\"apiKey\":null}}"},"code":"ERR_NETWORK","status":null}
13:46:55 | ERROR | Error in sendToJcApi {"message":"Network Error","name":"AxiosError","config":{"transitional":{"silentJSONParsing":true,"forcedJSONParsing":true,"clarifyTimeoutError":false},"transformRequest":[null],"transformResponse":[null],"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1,"maxBodyLength":-1,"env":{"FormData":null},"headers":{"Accept":"application/json, text/plain, */*","Content-Type":"application/json"},"cancelToken":{"promise":{"_h":1,"_i":0,"_j":null,"_k":{"onRejected":null,"promise":{"_h":0,"_i":0,"_j":null,"_k":null}}},"_listeners":[null]},"method":"post","url":"http://192.168.xx.xx/plugins/JeedomConnect/core/api/JeedomConnect.api.php","data":"{\"method\":\"PING\",\"jsonrpc\":\"2.0\",\"id\":xxxxxxxx,\"params\":{\"apiKey\":null}}"},"code":"ERR_NETWORK","status":null}
13:46:56 | ERROR | Error in sendToJcApi {"message":"Network Error","name":"AxiosError","config":{"transitional":{"silentJSONParsing":true,"forcedJSONParsing":true,"clarifyTimeoutError":false},"transformRequest":[null],"transformResponse":[null],"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1,"maxBodyLength":-1,"env":{"FormData":null},"headers":{"Accept":"application/json, text/plain, */*","Content-Type":"application/json"},"cancelToken":{"promise":{"_h":1,"_i":0,"_j":null,"_k":{"onRejected":null,"promise":{"_h":0,"_i":0,"_j":null,"_k":null}}},"_listeners":[null]},"method":"post","url":"http://192.168.xx.xx/plugins/JeedomConnect/core/api/JeedomConnect.api.php","data":"{\"method\":\"PING\",\"jsonrpc\":\"2.0\",\"id\":xxxxxxx,\"params\":{\"apiKey\":null}}"},"code":"ERR_NETWORK","status":null}
13:47:30 | INFO | App state changed to background

et si j’enrôle le téléphone, je n’ai pas de retour d’erreur mais les commandes ne fonctionnent pas quand je ne suis pas sur le réseau local.Voici les logs du client:

14:02:16 | ERROR | Error in sendToJcApi {"message":"Request failed with status code 401","name":"AxiosError","config":{"transitional":{"silentJSONParsing":true,"forcedJSONParsing":true,"clarifyTimeoutError":false},"transformRequest":[null],"transformResponse":[null],"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1,"maxBodyLength":-1,"env":{"FormData":null},"headers":{"Accept":"application/json, text/plain, */*","Content-Type":"application/json"},"cancelToken":{"promise":{"_h":1,"_i":0,"_j":null,"_k":{"onRejected":null,"promise":{"_h":0,"_i":0,"_j":null,"_k":null}}},"_listeners":[]},"method":"post","url":"https://xx.xx.xx.org/plugins/JeedomConnect/core/api/JeedomConnect.api.php","data":"{\"method\":\"SET_APPSTATE\",\"params\":{\"state\":\"active\",\"apiKey\":\"xxxxxxxxxxxxxx\"},\"jsonrpc\":\"2.0\",\"id\":xxxxx}"},"code":"ERR_BAD_REQUEST","status":401}
14:02:16 | ERROR | Error in sendToJcApi {"message":"Request failed with status code 401","name":"AxiosError","config":{"transitional":{"silentJSONParsing":true,"forcedJSONParsing":true,"clarifyTimeoutError":false},"transformRequest":[null],"transformResponse":[null],"timeout":0,"xsrfCookieName":"XSRF-TOKEN","xsrfHeaderName":"X-XSRF-TOKEN","maxContentLength":-1,"maxBodyLength":-1,"env":{"FormData":null},"headers":{"Accept":"application/json, text/plain, */*","Content-Type":"application/json"},"cancelToken":{"promise":{"_h":1,"_i":0,"_j":null,"_k":{"onRejected":null,"promise":{"_h":0,"_i":0,"_j":null,"_k":null}}},"_listeners":[]},"method":"post","url":"https://xx.xx.xx.org/plugins/JeedomConnect/core/api/JeedomConnect.api.php","data":"{\"method\":\"SET_APPSTATE\",\"params\":{\"state\":\"background\",\"apiKey\":\"xxxxxxxxxxx\"},\"jsonrpc\":\"2.0\",\"id\":xxxxxxxxxx}"},"code":"ERR_BAD_REQUEST","status":401}

Les logs semblent ressembler à ceux de ce topic même si la procédure ici est via polling et non via les webservices.

Peut etre que @chris_77 pourra t aider
Il utilise(ait ?) Traefik egalement par du ws.

1 « J'aime »

@tomitomas j’utilise toujours traefik et ça fonctionne nickel après avoir bataillé…
@gawin je lis les échanges et je regarde ce que je peux t’apporter en réponse

Bonsoir @gawin en faisant comme ça, tu ne passes pas par traefik.

Pour que traefik intercepte tout le trafic et le redirige vers les services concernés, je n’ouvre que 2 ports le 80 et le 443. Après j’utilise les rules afin de renvoyer le service à la bonne machine.

Après tu peux très bien utiliser la redirection de port… c’est ce que j’utilisai avant de tout passer sous traefik.

Voir la config du plugin JC, tu as peut être une erreur….

Effectivement chris_77 c’était l’idée de ne pas passer cette connexion par Traefik.

J’utilise Traefik couplé avec Authelia pour authentifier mes utilisateurs en SSO sur Jeedom et leur imposer l’authentification avec une clé Fido2.

Je souhaitais pour des questions de simplicité de gestion de l’application mobile m’affranchir de cette connexion et passer via le websocket qui authentifierait mes utilisateurs directement via un token mais j’avoue sécher un peu la et ne pas comprendre d’ou vient le probleme car la redirection semble bien fonctionnelle

Qui sort d ou ?
L authentification c est nous qui la gerons en lien avec le core, donc si tu as un autre system a cote forcement ca ne peut pas marcher et ca peut expliquer le 401 !

Non, je parlais du token fourni par Jeedom-Connect, la redirection se fait directement sur le port 8090, le but est justement de laisser Jeedom-Connect m’authentifier.

Ah ok !
Envoi moi une copie de ta configuration par mp stp

pardon … le temps que je recolle les morceaux …!

t’as redirection n’est valable que pour le websocket
or pour se connecter, l’application initialise une 1er connexion en http (pour les authentification, mais pas que!), puis ensuite la communication & échanges d’infos (update des cmd &co) se fait au travers du websocket.

du coup selon moi, la 1ere connexion va donc aller taper ton module sso, d’où le 401
Tu n as pas de log que Authelia pour verifier s il refuse pas des choses au meme moment ou tu scannes ton qrcode ?


je pense qu’il faut donc creuser sur les infos de @chris_77 vu ton architecture

D’accord, pourrais-tu m’en dire un peu plus sur ta config traefik, port ouvert… et post une capture d’écran de config du plugin JC en cachant les infos sensibles ….
Ça devrait permettre de t’aiguiller.

Port ouvert vers

  • traefik
  • websocket
  • ……

Merci pour vos explications et pour votre aide @tomitomas et @chris_77

Grace à vos conseils, j’ai repris ma configuration d’Authelia et effectivement, ça fonctionnait en interne car j’avais mis la policy en one_factor à la maison et donc l’authentification ne posait pas de probleme.

J’ai passé l’authentification en one_factor pour ce sous domaine ais toujours les mems erreurs, par contre si je passe en bypass ce sous domaine ça fonctionne parfaitement :slight_smile:

Je reroute les ports 80 et 443 vers mon traefik, le 8090 est adressé directement à la machine jeedom

Ci dessous mon configuration.yml d’authelia anonymisé avec la config pour jeedom en bypass:

jwt_secret: xxxxx

default_redirection_url: https://sso.xxxx.xxxx.org

log:
  file_path: /config/authelia.log
  level: trace 

server:
  host: 0.0.0.0
  port: 9091

identity_providers:
  oidc:
    hmac_secret: xxxxxxx
    issuer_private_key: | 
      -----BEGIN RSA PRIVATE KEY-----
      xxxxxxxxx
      -----END RSA PRIVATE KEY-----
    access_token_lifespan: 1h
    authorize_code_lifespan: 1m
    id_token_lifespan: 1h
    refresh_token_lifespan: 90m
    enable_client_debug_messages: false
    clients:
      - id: nextcloud
        description: Cloud Perso
        secret: xxxxxxxx
        public: false
        authorization_policy: one_factor
        audience: []
        scopes:
          - openid
          - groups
          - email
          - profile
        redirect_uris:
          - https://cloud.xxxx.xxxx.org/apps/oidc_login/oidc
        grant_types:
          - refresh_token
          - authorization_code
        response_types:
          - code
        response_modes:
          - form_post
          - query
          - fragment
        userinfo_signing_algorithm: none

      - id: bookstack
        description: Ma doc
        secret: xxxxxxxxx
        public: false
        authorization_policy: one_factor
        audience: []
        scopes:
          - openid
          - groups
          - email
          - profile
        redirect_uris:
          - https://doc.xxxx.xxxxx.org/oidc/callback
        grant_types:
          - refresh_token
          - authorization_code
        response_types:
          - code
        response_modes:
          - form_post
          - query
          - fragment
        userinfo_signing_algorithm: none


totp:
  issuer: authelia.com
  period: 30

authentication_backend:
  disable_reset_password: false
  refresh_interval: 5m
  ldap:
    implementation: custom
    url: ldap://ldap
    timeout: 5s
    start_tls: false
    base_dn: dc=xxxxx,dc=xxxx,dc=org
    users_filter: (&({username_attribute}={input})(objectClass=inetOrgPerson))
    additional_users_dn: ou=People
    mail_attribute: mail
    additional_groups_dn: ou=group
    groups_filter: (&(member={dn})(objectClass=groupOfNames))
    user: cn=admin,dc=xxxxx,dc=xxxx,dc=org
    password: xxxxx

access_control:
  default_policy: two_factor 
  
  rules:
    - domain: "domotique.xxxxx.xxxx.org"
      policy: bypass
    
    - domain: "*.xxxxx.xxxxx.org"
      policy: one_factor 
      networks:
      - 192.168.xx.x/24
      - xx.xx.xx.xx/32


session:
  name: authelia_session
  secret: xxxxx
  expiration: 3600
  inactivity: 300
  domain: xxx.xxx.org

regulation:
  max_retries: 3
  find_time: 120
  ban_time: 300

storage:
  encryption_key: xxxxxxx
  local:
    path: /config/db.sqlite3

notifier:
  #filesystem:
  #  filename: /config/notification.txt
  smtp:
    username: "xxxxxx@gmail.com"
    # Password can also be set using a secret: https://www.authelia.com/docs/configuration/secrets.html
    password: "xxxxxx"
    sender: "xxxxx@gmail.com"
    host: smtp.gmail.com
    port: 587

à cloturer du coup !
merci

Ce sujet a été automatiquement fermé après 24 heures suivant le dernier commentaire. Aucune réponse n’est permise dorénavant.