What is Single Sign On?
Single Sign On is a technology by which a user, being authenticated on a certification
authority (hereinafter Identity Provider, IdP) , will be automatically authenticated on another service
(hereinafter referred to as Service Provider, SP or Consumer [1-N]) of this company.
The Single Sign On mechanism is used by such sites as
HabraHabr ,
Yandex ,
Google . The advantages of this approach to user authentication are obvious:
- User enters password only 1 time
- Or does not enter the password on IdP at all, if the input was used there through a social network or using OpenID
- Automatically authenticates to all company projects.
- User data can float between services from IdP to SP transparent for user
The minuses, of course, follow, as always, from the pros:
')
- Loss of the password from IdP entails the problem of entering all services
- Potentially increased risk of theft of a master session with IdP (can be reduced by linking the session to the provider's subnet, as well as using HTTPS , HTTP Only Cookies and SSL Only Cookies )
- Potentially increased risk of password theft from IdP
- ...
Despite this, from a business point of view, as well as user experience, the implementation of this functionality outweighs all the disadvantages, and the epic on the implementation of SSO in the company begins.
Before proceeding with the implementation of SSO in the company, it would be good to make sure that you are well aware of what it is:
and even better, how to apply them yourself .This is important because incorrect implementation of SSO can lead to critical errors in all services that are connected to SSO: from compromising user data in one service, ending with hijacking an account in IdP, which leads to compromise of data in all services.
On Habré there is another great article on the basic principles of working with cookies and how to properly set cookies so as not to remain without pants:
habrahabr.ru/company/mailru/blog/228997 .
So, after getting acquainted with the basic theory: what is SSO, security aspects that are associated with this task - we can begin to implement it.
How it will work
In general, authentication will take place in the following scenario:

Consider the scenario when the user goes to any page protected by authorization through the bookmarks
(paragraph 1 in the diagram) .
Next, in Symfony2, the
Entry point mechanism is activated and redirects us to our IdP, where we have to drop the OTP. There are several scenarios for the development of events:
- The user is authenticated to IdP, then IdP simply docks into the OTP redirection chain ( step 3 in the diagram, green line)
- The user is not authenticated to IdP, then he should be sent to the login / password input form (paragraph 3 on the diagram, red line)
- The user generally sees us for the first time, but wants to register and goes to the registration form (At this point, the SP from which he came is saved on the IdP session.)
After the user, for example, has registered, he should be redirected to step 3 along the green line for OTP validation to SP, from which he came to us on IdP. When we validate OTP on SP, we make a trusted REST request to our IdP to make sure that such OTP really exists and has not expired in time. At this point, the REST service should invalidate this OTP.
Put Lok, this operation must be atomic . Further requests with this OTP should return either HTTP 400 or HTTP 404 for SP.
In the case where IdP responded that such an OTP exists and is valid, SP authenticates the user by issuing a PreAuthenticatedToken to it.
The output will work as follows:

Please note that this type of output is considered from the point of view of the beginning of the process on the SP. This is important because the user will be returned to where he started the operation.
Suppose the user was on a certain page
/ secured_area and clicked on "Exit". At this point, a local logout occurs within SP. Then we go to IdP at a special URL
/ sso / logout , which will manage the exit from all services for this user. Since since the user has already arrived with SP, then IdP selects the next service that is in the company, and sends it to make an exit. That service, in turn, again upon completion, sends us to IdP and if the services are over, it performs a local exit (Section 5 in the diagram). After the user is sent back to the SP, from which he began to make an exit.
There is another scenario in which the user begins the process of exiting not from SP but from IdP. And it looks like this:

Certification Authority (IdentityProvider)
To make a certification center, you must first select an application in your company that will be responsible for this, like it was done in Yandex (Yandex.Passport) or in Google (Google Accounts).
In this application we will install the first part:
SingleSignOnIdentityProviderBundleSingleSignOnIdentityProviderBundle is responsible for:
- One-time password generation ( OTP )
- Remembers in session, from which SP the user came
- Functionality for exit from all SPs
We put through the composer:
php composer.phar require "korotovsky/sso-idp-bundle:~0.2.0"
Next, update the dependencies and write our bundle in AppKernel:
We connect routes
/ sso / login and
/ sso / logout from the bundle:
app / config / routing.yml # app/config/routing.yml: sso: resource: . type: sso
Now configure the IdP bundle:
app / config / config.yml # app/config/config.yml: krtv_single_sign_on_identity_provider: host: idp.example.com # IdP host_scheme: http # IdP . login_path: /sso/login/ # , OTP logout_path: /sso/logout # , services: - consumer1 # SP , otp_parameter: _otp # OTP secret_parameter: secret # Dependency Injection , # .
Rule security.yml:
app / config / security.yml # app/config/security.yml security: access_control: - { path: ^/sso/login$, roles: [ROLE_USER, IS_AUTHENTICATED_FULLY] }
Now you need to register SP in our bundle, for this we will create a class that immenment the
\ Krtv \ Bundle \ SingleSignOnIdentityProviderBundle \ Manager \ ServiceProviderInterface interface and register it in the service container using the tag
src / Acme / Bundle / AppBundle / Resources / config / security.yml services: acme_bundle.sso.consumer1: class: Acme\Bundle\AppBundle\Sso\ServiceProviders\ServiceProvider1 tags: - { name: sso.service_provider, service: consumer1 }
Bundle Public API
This bundle registers with Dependency Injection several services that will be useful when customizing SSO processes in the final project.
This completes the IdP setup, proceed to the SP setup.
The application in which you want to authenticate the user via IdP should set itself
SingleSignOnServiceProviderBundleSingleSignOnServiceProviderBundle is responsible for:
- Automatic IdP Authentication
We put through the composer:
php composer.phar require "korotovsky/sso-sp-bundle:~0.2.0"
Next, update the dependencies and write our bundle in AppKernel:
We connect the route
/ otp / validate / for OTP validation:
app / config / routing.yml # app/config/routing.yml: otp: # this needs to be the same as the check_path, specified later on in security.yml path: /otp/validate/
Now configure the IdP bundle:
app / config / config.yml # app/config/config.yml: krtv_single_sign_on_service_provider: host: idp.example.com # IdP host_scheme: http # IdP . login_path: /sso/login/ # OTP # Configuration for OTP managers otp_manager: name: http managers: http: provider: service # Active provider for HTTP OTP manager providers: # Available HTTP providers service: id: acme_bundle.your_own_fetch_service.id guzzle: client: acme_bundle.guzzle_service.id resource: http://idp.example.com/internal/v1/sso otp_parameter: _otp # OTP secret_parameter: secret # Dependency Injection , # .
In order for us to have an “honest” SSO, we need to choose the
http method as a manager, and choose a
service as a provider. To do this, you must implement the
Krtv \ SingleSignOn \ Manager \ Http \ Provider \ ProviderInterface interface.
Rule security.yml:
app / config / security.yml # app/config/security.yml firewalls: main: pattern: ^/ sso: require_previous_session: false provider: main check_path: /otp/validate/ # Same as in app/config/routing.yml sso_scheme: http # Required sso_host: idp.example.com # Required sso_otp_scheme: http # Optional sso_otp_host: consumer1.com # Optional sso_failure_path: /login sso_path: /sso/login/ # SSO endpoint on IdP. sso_service: consumer1 # Consumer name logout: invalidate_session: true path: /logout target: http://idp.example.com/sso/logout?service=consumer1
Bundle Public API
This bundle registers with Dependency Injection several services that will be useful when customizing SSO processes in the final project.
This completes the configuration of our applications.
To keep track of updates to bundles, put asterisks for them: