hslavich / OneloginSamlBundle

OneLogin SAML Bundle for Symfony
MIT License
149 stars 94 forks source link

OneLogin integration #26

Closed VincentClair closed 7 years ago

VincentClair commented 7 years ago

Hello,

I have configured the bundle with Onelogin IdP, with the SAML Test Connector: https://support.onelogin.com/hc/en-us/articles/202673944-How-to-Use-the-OneLogin-SAML-Test-Connector

I don't succeed in making works one thing: once i am connected with onelogin, the service does not redirect me to my local application. The page doesn't give any error. RelayState in URL is set to "http://mylocaldomain.dev/saml/login".

What mistake I made ? Is the RelayState value valid ? Maybe it could make a loop if it stay on "saml/login"... If i dig in code, the $return parameter from $this->get('onelogin_auth')->login(); in SamlController::loginAction is not set. Should it be a page URL from my application ?

Hope you could help me. Thank you

hslavich commented 7 years ago

Hi, Do you set ACS URL with something like "http://mylocaldomain.dev/app_dev.php/saml/acs"? Also, don't set any RelayState, that could make a login loop. The idp should redirect to acs url, and then the application finish the authentication process.

VincentClair commented 7 years ago

Yes, i set it with "http://mylocaldomain.dev/saml/acs".

Please find here my config.yml:

# SSO
hslavich_onelogin_saml:
    debug: "%kernel.debug%"
    # Basic settings
    idp:
        entityId: '%sso_saml_ipd_id%'
        singleSignOnService:
            url: '%sso_saml_ipd_sso_url%'
            binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'
        singleLogoutService:
            url: '%sso_saml_ipd_slo_url%'
            binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'
        x509cert: '%sso_saml_ipd_cert%'
    sp:
        entityId: '%sso_saml_sp_id%'
        assertionConsumerService:
            url: '%sso_saml_sp_acs_url%'
            binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
        singleLogoutService:
            url: '%sso_saml_sp_slo_url%'
            binding: 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'

and my parameters.yml:

    sso_enabled: true
    sso_saml_ipd_id: 'https://...'
    sso_saml_ipd_sso_url: 'https://...'
    sso_saml_ipd_slo_url: 'https://...'
    sso_saml_ipd_cert: |
      -----BEGIN CERTIFICATE-----
      ...
      -----END CERTIFICATE-----
    sso_saml_sp_id: 'https://mylocaldomain.dev/saml/metadata'
    sso_saml_sp_acs_url: 'https://mylocaldomain.dev/saml/acs'
    sso_saml_sp_slo_url: 'https://mylocaldomain.dev/saml/logout'
    sso_saml_sp_cert: null
    sso_saml_sp_private_key: null
BillKeenan commented 7 years ago

exactly that, which needs to match what you have in your firewall setting

security:
    firewalls:
        default:
          saml:
              username_attribute: email
              check_path: /saml/acs
              login_path: /saml/login
              failure_path: /login
              always_use_default_target_path: true
              provider: saml_provider

          # Traditional login form
            form_login:
                login_path: /login
                check_path: /login_check
                always_use_default_target_path: true
                provider: form_provider
          #as per https://github.com/symfony/symfony/issues/5320

    providers:
        saml_provider:
            id: saml_user_provider
        form_provider:
            id: user_provider
VincentClair commented 7 years ago

Here is my security.yml:

    providers:
        fos_userbundle:
            #id: fos_user.user_provider.username
            id: fos_user.user_provider.username_email

        #saml_provider:
            # Basic provider instantiates a user with default roles
        #    saml:
        #        user_class: Loyalty\UserBundle\Model\User
        #        default_roles: ['ROLE_USER']

    firewalls:
        login:
            pattern: ^/auth/form$
            anonymous: true

        saml:
            pattern:    ^/
            anonymous: true
            saml:
                #username_attribute: uid
                check_path: /saml/acs
                login_path: /saml/login
            logout:
                path: /saml/logout

It lacks maybe the parameters always_use_default_target_path and provider. I wil try it.

VincentClair commented 7 years ago

It seems that this is not a problem with always_use... nor provider.

Set them or not, I could see the following logs:

[2016-09-27 16:07:40] request.INFO: Matched route "saml_acs". {"route_parameters":{"_controller":"Hslavich\\OneloginSamlBundle\\Controller\\SamlController::assertionConsumerServiceAction","_route":"saml_acs"},"request_uri":"https://loyalty.dev/saml/acs"} []
[2016-09-27 16:07:40] doctrine.DEBUG: SELECT t0.username AS username_1, t0.username_canonical AS username_canonical_2, t0.email AS email_3, t0.email_canonical AS email_canonical_4, t0.enabled AS enabled_5, t0.salt AS salt_6, t0.password AS password_7, t0.last_login AS last_login_8, t0.locked AS locked_9, t0.expired AS expired_10, t0.expires_at AS expires_at_11, t0.confirmation_token AS confirmation_token_12, t0.password_requested_at AS password_requested_at_13, t0.credentials_expired AS credentials_expired_14, t0.credentials_expire_at AS credentials_expire_at_15, t0.id AS id_16, t0.ws_id AS ws_id_17, t0.profile_id AS profile_id_18 FROM user t0 WHERE t0.username_canonical = ? LIMIT 1 ["some.username"] []
[2016-09-27 16:07:40] doctrine.DEBUG: SELECT t0.id AS id_1, t0.my_key AS my_key_2 FROM role t0 INNER JOIN user_role ON t0.id = user_role.role_id WHERE user_role.user_id = ? ["[...]"] []
[2016-09-27 16:07:40] security.INFO: User has been authenticated successfully. {"username":"some.username"} []
[2016-09-27 16:07:40] doctrine.DEBUG: "START TRANSACTION" [] []
[2016-09-27 16:07:40] doctrine.DEBUG: UPDATE user SET last_login = ? WHERE id = ? ["2016-09-27 16:07:40","[...]"] []
[2016-09-27 16:07:40] doctrine.DEBUG: "COMMIT" [] []
[2016-09-27 16:07:40] security.DEBUG: Stored the security token in the session. {"key":"_security_saml"} []

The process stays on the URL "https://some.idp.../adfs/ls/?SAMLRequest=fVNN...&RelayState=https%3A%2F%2Fmylocaldomain.dev%2Fsaml%2Flogin" with a white page. No errors in the console. If i dig in the HTML code source, i could see the form and js that POST the message to /saml/acs URL.

I have tested the process on two different IdP (OneLogin and and internal LDAP) and 2 browsers (Chrome and Firefox): the result is the same. Have you another idea?

VincentClair commented 7 years ago

Maybe here is another way. I am using FOSRest, so there is some listeners that interacts with HTTP requests. As i see in console, /saml/acs return an empty body with a 204 HTTP code. Is is the expecting behavior ?

hslavich commented 7 years ago

Paste your access_control config and make sure that the loaded user has the needed roles.

VincentClair commented 7 years ago

access_control is ok, as if i reload the application, the user could access to it.

But here is it:

    access_control:
        - { path: ^/program, role: IS_AUTHENTICATED_ANONYMOUSLY, methods: [GET] }
        - { path: ^/module, role: IS_AUTHENTICATED_ANONYMOUSLY, methods: [GET] }
        - { path: ^/ui/options, role: IS_AUTHENTICATED_ANONYMOUSLY, methods: [GET] }
        - { path: ^/features, role: IS_AUTHENTICATED_ANONYMOUSLY, methods: [GET] }
        - { path: ^/style/app.css, role: IS_AUTHENTICATED_ANONYMOUSLY, methods: [GET] }
        - { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY, methods: [POST] }
        - { path: ^/users/register, role: IS_AUTHENTICATED_ANONYMOUSLY, methods: [POST] }
        - { path: ^/api/doc, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/graphql, role: IS_AUTHENTICATED_ANONYMOUSLY, methods: [POST] }
        - { path: ^/graphiql, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/saml/login, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/saml/metadata, roles: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/, role: ROLE_USER }
VincentClair commented 7 years ago

Thanks for your help. I have finally found the problem. It is some listeners that intercept all HTTP requests and treat them as REST. I have fixed my problem.

aaronahearne commented 6 years ago

@VincentClair why didnt you leave your solution??

arturslogins commented 5 years ago

It seems that this is not a problem with always_use... nor provider.

Set them or not, I could see the following logs:

[2016-09-27 16:07:40] request.INFO: Matched route "saml_acs". {"route_parameters":{"_controller":"Hslavich\\OneloginSamlBundle\\Controller\\SamlController::assertionConsumerServiceAction","_route":"saml_acs"},"request_uri":"https://loyalty.dev/saml/acs"} []
[2016-09-27 16:07:40] doctrine.DEBUG: SELECT t0.username AS username_1, t0.username_canonical AS username_canonical_2, t0.email AS email_3, t0.email_canonical AS email_canonical_4, t0.enabled AS enabled_5, t0.salt AS salt_6, t0.password AS password_7, t0.last_login AS last_login_8, t0.locked AS locked_9, t0.expired AS expired_10, t0.expires_at AS expires_at_11, t0.confirmation_token AS confirmation_token_12, t0.password_requested_at AS password_requested_at_13, t0.credentials_expired AS credentials_expired_14, t0.credentials_expire_at AS credentials_expire_at_15, t0.id AS id_16, t0.ws_id AS ws_id_17, t0.profile_id AS profile_id_18 FROM user t0 WHERE t0.username_canonical = ? LIMIT 1 ["some.username"] []
[2016-09-27 16:07:40] doctrine.DEBUG: SELECT t0.id AS id_1, t0.my_key AS my_key_2 FROM role t0 INNER JOIN user_role ON t0.id = user_role.role_id WHERE user_role.user_id = ? ["[...]"] []
[2016-09-27 16:07:40] security.INFO: User has been authenticated successfully. {"username":"some.username"} []
[2016-09-27 16:07:40] doctrine.DEBUG: "START TRANSACTION" [] []
[2016-09-27 16:07:40] doctrine.DEBUG: UPDATE user SET last_login = ? WHERE id = ? ["2016-09-27 16:07:40","[...]"] []
[2016-09-27 16:07:40] doctrine.DEBUG: "COMMIT" [] []
[2016-09-27 16:07:40] security.DEBUG: Stored the security token in the session. {"key":"_security_saml"} []

The process stays on the URL "https://some.idp.../adfs/ls/?SAMLRequest=fVNN...&RelayState=https%3A%2F%2Fmylocaldomain.dev%2Fsaml%2Flogin" with a white page. No errors in the console. If i dig in the HTML code source, i could see the form and js that POST the message to /saml/acs URL.

I have tested the process on two different IdP (OneLogin and and internal LDAP) and 2 browsers (Chrome and Firefox): the result is the same. Have you another idea?

Can you please post your solution, because i have the same issue

VincentClair commented 5 years ago

Sorry, i have no more the solution, as I worked for a client project. The listener which intercept all HTTP requests has nothing with this bundle and was proprietary, so in my opinion, there is no real general solution to this problem.

tigergardens commented 2 years ago

Hello, I am having the same problem today with symfony 6 and oneloginsaml bundle. I've tried everything but nothing works. The sso auth works well in "app_env=dev" mode, but when i turn it to prod, i have the issue : white page and login loop...

If someone have encounter the same issue, please HELP ME !!!

this is my conf:

/***** security.yaml ******/
security:
    providers:
        user_mongo:
            mongodb:
                class: App\Document\User
                property: username

        saml_provider:
            ##  Basic provider instantiates a user with identifier and default roles
            saml:
                user_class: 'App\Document\User'
                default_roles: ['ROLE_USER']

        all_users:
            chain:
                providers: ['user_mongo','saml_provider']

    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        api:
            pattern: ^/api
            stateless: true
            logout: false

        main:
            lazy: true
            provider: all_users

            saml:
                identifier_attribute: UserID
                check_path: saml_acs
                login_path: saml_login

            logout:
                path: saml_logout

    access_control:
        # PROD CONFIG
        - { path: ^/admin,                      roles: ROLE_ADMIN }
        - { path: ^/api,                        roles: PUBLIC_ACCESS }
        - { path: ^/saml/(metadata|login|acs),  roles: PUBLIC_ACCESS }
        - { path: ^/,                           roles: ROLE_USER }

Thank you !

a-menshchikov commented 2 years ago

@tigergardens This bundle is not compatible with Symfony 6. Could you try the nbgrp/onelogin-saml-bundle instead?

tigergardens commented 2 years ago

@tigergardens This bundle is not compatible with Symfony 6. Could you try the nbgrp/onelogin-saml-bundle instead?

Hello Alexander, my bad, i use the right bundle you mentioned. Thanks for your answer, i found my problem. It was inside the doctrine mongo db config... when i change auto_generate_proxy_classes from false to true. Everything works well...I don't really know why this happen.