Symfony 3 - Legacy Authentication Bridge - straight md5

If you are building a system which needs a fallback authentication system to welcome existing users into a new application architecture, you will need to support the authentication approach of the legacy application.

One very common method is to md5 the password and store it in the database. Symfony supports md5 password encoders, but needs a little extra configuration to disable the salt.

This post shows how to configure a connection into the legacy database, chain the authentication providers, and configure the password encoder.

I chose to put all the code that is strictly operating on the legacy system in its own bundle with the rationale that it may be removed in the future. If it isn't removed, it should be easier to set the context of tasks when working in the different bundles.

If you are transitioning from a legacy application to a new architecture, you will probably have two databases - one for the old system and one for the new one. The first step is to set up Symfony and Doctrine to connect to both.

app/config/config.yml

    dbal:
        default_connection: default
        connections:
            default:
                driver:   "%database_driver%"
                host:     "%database_host%"
                port:     "%database_port%"
                dbname:   "%database_name%"
                user:     "%database_user%"
                password: "%database_password%"
                charset:  UTF8
                
            legacy:
                driver:   '%legacy_database_driver%'
                host:     '%legacy_database_host%'
                port:     '%legacy_database_port%'
                dbname:   '%legacy_database_name%'
                user:     '%legacy_database_user%'
                password: '%legacy_database_password%'
                charset:  UTF8

     ...

    orm:
        auto_generate_proxy_classes: "%kernel.debug%"
        default_entity_manager: default

        entity_managers:
            default:        
                auto_mapping: true
                mappings:
                    AppBundle: ~
            legacy:
                connection: legacy
                mappings:                    
                    LegacyBridgeBundle: ~

Then you need to create the user provider as described here http://symfony.com/doc/current/cookbook/security/entity_provider.html. Be sure to make any column name updates and ensure they are reflected in the config files as well.

This is a fallback configuration, with the FOS User Bundle as the first provider (Ref: http://symfony.com/doc/current/cookbook/security/multiple_user_providers.html) and the legacy provider running next.

Add the legacy provider into your chain as follows:

app/config/security.yml


imports:
    - { resource: "@LegacyBridgeBundle/Resources/config/security.yml" }

security:

    ...

    providers:
        chain_provider:
            chain:
                providers: [ fos_userbundle, legacy_user_provider ]

    ...

        main:
            pattern: ^/
            form_login:
                provider: chain_provider

And set up the encoder the bundle security.yml

security.yml


security:
    encoders:
        LegacyBridgeBundle\Entity\LegacyUser: 
            algorithm: md5
            encode_as_base64: false
            iterations: 0
       
    providers:
        legacy_user_provider:
            entity: 
                class: LegacyBridgeBundle:LegacyUser
                property: username
                manager_name: legacy

Please note that I'm not recommending unsalted md5 (I do recommend unsalted butter), but sharing an approach that allows the authentication to run against an existing database.