bloggers bloggers

Marco Napolitano
Messaggi: 79
Stelle: 0
Data: 17/02/22
Jader Jed Francia
Messaggi: 63
Stelle: 0
Data: 18/02/21
Paolo Gambetti
Messaggi: 2
Stelle: 0
Data: 11/11/19
Katia Pazzi
Messaggi: 1
Stelle: 0
Data: 27/06/19
Ezio Lombardi
Messaggi: 11
Stelle: 0
Data: 10/04/18
Chiara Mambretti
Messaggi: 25
Stelle: 0
Data: 27/02/17
Serena Traversi
Messaggi: 3
Stelle: 0
Data: 21/07/16
Francesco Falanga
Messaggi: 8
Stelle: 0
Data: 14/06/16
Antonio Musarra
Messaggi: 2
Stelle: 0
Data: 18/11/13
Simone Celli Marchi
Messaggi: 6
Stelle: 0
Data: 09/07/13
Indietro

Integrazione Liferay - Cas server: Autenticazione tramite facebook/linkedin

Ho avuto la necessità di integrare liferay 6.2 con un cas server per la gestione della login centralizzata. In questo post vedremo come autenticarci tramite facebook/linkedin attravero il cas.

Per prima cosa scarichiamo il cas-overlay (nel mi caso quello relativo alla versione 5.0.4)
Modifichiamo il build.gradle aggiungendo le seguenti dipendenze

  compile "org.apereo.cas:cas-server-support-ldap:${project.'cas.version'}"
compile "org.apereo.cas:cas-server-support-pac4j-webflow:${project.'cas.version'}"

    
La prima è relativa al supporto ldap (facoltativa) la seconda è relativa alle librerie pac4j che saranno utilizzate dal cas server per delegare l'autenticazione presso sistemi terzi (facebook/linkdin nel nostro caso)

Una volta compilato e deployato il war, modifichiamo il file application.properties

Aggiungiamo le properties relative a linkedin

cas.authn.pac4j.linkedIn.id=<app_id>
cas.authn.pac4j.linkedIn.secret=<app_secret>
cas.authn.pac4j.linkedIn.fields=id,first-name,last-name,email-address,picture-url,positions
cas.authn.pac4j.linkedIn.scope=r_basicprofile,r_emailaddress

e quelle relative a facebook (i fields e gli scope compilati sono quelli approvati automaticamente alla creazione dell'app)

cas.authn.pac4j.facebook.fields=id,name,first_name,last_name,gender,locale,languages,link,timezone,updated_time,verified,email,picture
cas.authn.pac4j.facebook.id=<app_id>
cas.authn.pac4j.facebook.secret=app_secret>
cas.authn.pac4j.facebook.scope=email,public_profile,user_friends

Settiamo le url del cas (verranno usate per le url di redirect)

cas.server.name=https://<cas-server-host>:<port>
cas.server.prefix=https://<cas-server-host>:<port>/cas-server

Aggiungiamo la seguente property. Questa verrà utilizzata per far si che il principal venga popolato con un indicazione
del sistema su cui ci siamo autenticati

  • cas.authn.pac4j.typedIdUsed=true

Es:  org.pac4j.oauth.profile.facebook.FacebookProfile#<facebook_principal_id>

Abilitiamo il cas (utilizzando il protollo cas3) a rilasciare gli attributi opzionali a sistemi terzi (nel nostro caso Liferay)

cas.view.cas3.releaseProtocolAttributes=true

e configuriamo gli attributi che andranno propagati di default

cas.authn.attributeRepository.defaultAttributesToRelease=id,access_token,firstName,lastName,emailAddress,email,first_name,last_name,gender,locale    

La configurazione del cas è terminata.

Ora dobbiamo modificare Liferay per recepire queste configurazioni.
Creiamo un ext plugin e aggiungiamo alla cartella ext-lib/portal

  1. cas-client-core-3.4.1.jar (la versione utlizzata dal cas 5.0.4, rinominandola il cas-client-core.jar)
  2. cas-client-integration-tomcat-v7-3.4.1.jar

Facciamo override del cas filter modificando il metoto

protected TicketValidator getTicketValidator(long companyId)
            throws Exception {

        TicketValidator ticketValidator = _ticketValidators.get(companyId);

        if (ticketValidator != null) {
            return ticketValidator;
        }

        String serverName = PrefsPropsUtil.getString(companyId,
                PropsKeys.CAS_SERVER_NAME, PropsValues.CAS_SERVER_NAME);
        String serverUrl = PrefsPropsUtil.getString(companyId,
                PropsKeys.CAS_SERVER_URL, PropsValues.CAS_SERVER_URL);
        String loginUrl = PrefsPropsUtil.getString(companyId,
                PropsKeys.CAS_LOGIN_URL, PropsValues.CAS_LOGIN_URL);

        Cas30ProxyTicketValidator cas30ProxyTicketValidator = new Cas30ProxyTicketValidator(
                serverUrl);

        Map<String, String> parameters = new HashMap<String, String>();

        parameters.put("serverName", serverName);
        parameters.put("casServerUrlPrefix", serverUrl);
        parameters.put("casServerLoginUrl", loginUrl);
        parameters.put("redirectAfterValidation", "false");

        cas30ProxyTicketValidator.setCustomParameters(parameters);

        _ticketValidators.put(companyId, cas30ProxyTicketValidator);

        return cas30ProxyTicketValidator;
    }

in modo da ulizzare Cas30ProxyTicketValidator invece di Cas20ProxyTicketValidator. In questo modo anche Liferay utilizzerà il protocollo CAS3 per la verifica del ticket.

Modifichiamo il processFilter dopo la parte di validazione

    Assertion assertion = ticketValidator.validate(ticket, serviceUrl);

            if (assertion != null) {
                AttributePrincipal attributePrincipal = assertion
                        .getPrincipal();

                login = attributePrincipal.getName();

                if (_log.isInfoEnabled()) {
                    _log.info("Cas Login string [" + login + "]");
                }
                //in questa mappa sono contenuti tutti gli attributi propagati da cas
                Map<String, Object> attributes = attributePrincipal
                        .getAttributes();

                if (_log.isInfoEnabled()) {
                    _log.info("Cas attributes for social login" + attributes);
                }
                //nel caso di una login direttamente da cas e non da social network
                if (Validator.isEmailAddress(login)) {
                    session.setAttribute(WebKeys.CAS_LOGIN, login);
                } else {

                    String[] casProfile = StringUtil.split(login,
                            StringPool.POUND);

                    String className = casProfile[0];
                    String id = casProfile[1];

                    ProfileBean profileBean = new ProfileBean();

                    String accessToken = MapUtil.getString(attributes,
                            CasConstants.ACCESS_TOKEN);

                    profileBean.setAccessToken(accessToken);
                    profileBean.setId(id);

                    if (StringUtil.equalsIgnoreCase(className,
                            CasConstants.FACEBOOK_PAC4J_CLASSNAME)) {

                        String emailAddress = MapUtil.getString(attributes,
                                CasConstants.FACEBOOK_EMAIL);
                        String firstName = MapUtil.getString(attributes,
                                CasConstants.FACEBOOK_FIRST_NAME);
                        String lastName = MapUtil.getString(attributes,
                                CasConstants.FACEBOOK_LAST_NAME);
                        String gender = MapUtil.getString(attributes,
                                CasConstants.FACEBOOK_GENDER);
                        String locale = MapUtil.getString(attributes,
                                CasConstants.FACEBOOK_LOCALE);

                        profileBean.setEmailAddress(emailAddress);
                        profileBean.setFirstName(firstName);
                        profileBean.setLastName(lastName);
                        profileBean.setGender(gender);
                        profileBean.setLocale(locale);
                        profileBean.setType(CasConstants.FACEBOOK_TYPE);

                    } else if (StringUtil.equalsIgnoreCase(className,
                            CasConstants.LINKEDIN_PAC4J_CLASSNAME)) {

                        String emailAddress = MapUtil.getString(attributes,
                                CasConstants.LINKEDIN_EMAIL);
                        String firstName = MapUtil.getString(attributes,
                                CasConstants.LINKEDIN_FIRST_NAME);
                        String lastName = MapUtil.getString(attributes,
                                CasConstants.LINKEDIN_LAST_NAME);

                        profileBean.setEmailAddress(emailAddress);
                        profileBean.setFirstName(firstName);
                        profileBean.setLastName(lastName);
                        profileBean.setType(CasConstants.LINKEDIN_TYPE);

                    }

                    session.setAttribute(CasConstants.PROFILE_BEAN, profileBean);

                }

In questo modo recuperiamo gli attributi propagati dal cas, popoliamo un oggetto che verrà messo in sessione e  che sarà utilizzato dalle classi di autologin per creare/loggare l'utente.

Di seguito un'implementazione della FacebookAutoLogin

@Override
    protected String[] doLogin(HttpServletRequest request,
            HttpServletResponse response) throws Exception {

        HttpSession session = request.getSession();

        ProfileBean profileBean = (ProfileBean) session
                .getAttribute(CasConstants.PROFILE_BEAN);

        String[] credentials = new String[3];

        if (Validator.isNotNull(profileBean) && profileBean.isFacebook()) {
            long companyId = PortalUtil.getCompanyId(request);
            User user = getUser(session, companyId);

            if (user == null) {
                user = _addUser(companyId, profileBean);
            }


            credentials[0] = String.valueOf(user.getUserId());
            credentials[1] = user.getPassword();
            credentials[2] = Boolean.FALSE.toString();
        }

        return credentials;
    }

    protected User getUser(HttpSession session, long companyId)
            throws PortalException, SystemException {

        ProfileBean profileBean = (ProfileBean) session
                .getAttribute(CasConstants.PROFILE_BEAN);

        if (Validator.isNotNull(profileBean.getEmailAddress())) {
            session.removeAttribute(CasConstants.PROFILE_BEAN);

            return UserLocalServiceUtil.fetchUserByEmailAddress(companyId,
                    profileBean.getEmailAddress());
        } else {
            long facebookId = GetterUtil.getLong(profileBean.getId());

            if (facebookId > 0) {
                return UserLocalServiceUtil.fetchUserByFacebookId(companyId,
                        facebookId);
            }
        }

        return null;
    }

    private User _addUser(long companyId, ProfileBean profileBean)
            throws PortalException, SystemException {

        long creatorUserId = 0;
        boolean autoPassword = true;
        String password1 = StringPool.BLANK;
        String password2 = StringPool.BLANK;
        boolean autoScreenName = true;
        String screenName = StringPool.BLANK;
        String emailAddress = profileBean.getEmailAddress();
        long facebookId = GetterUtil.getLong(profileBean.getId());
        String openId = StringPool.BLANK;
        Locale locale = LocaleUtil.getDefault();
        String firstName = profileBean.getFirstName();
        String middleName = StringPool.BLANK;
        String lastName = profileBean.getLastName();
        int prefixId = 0;
        int suffixId = 0;
        boolean male = Validator.equals(profileBean.getGender(), "male");
        int birthdayMonth = Calendar.JANUARY;
        int birthdayDay = 1;
        int birthdayYear = 1970;
        String jobTitle = StringPool.BLANK;
        long[] groupIds = null;
        long[] organizationIds = null;
        long[] roleIds = null;
        long[] userGroupIds = null;
        boolean sendEmail = true;

        ServiceContext serviceContext = new ServiceContext();

        User user = UserLocalServiceUtil.addUser(creatorUserId, companyId,
                autoPassword, password1, password2, autoScreenName, screenName,
                emailAddress, facebookId, openId, locale, firstName,
                middleName, lastName, prefixId, suffixId, male, birthdayMonth,
                birthdayDay, birthdayYear, jobTitle, groupIds, organizationIds,
                roleIds, userGroupIds, sendEmail, serviceContext);

        user = UserLocalServiceUtil.updateLastLogin(user.getUserId(),
                user.getLoginIP());

        user = UserLocalServiceUtil
                .updatePasswordReset(user.getUserId(), false);

        user = UserLocalServiceUtil.updateEmailAddressVerified(
                user.getUserId(), true);

        return user;

    }

Se tutto è andato a buon fine ci trovermo autenticati con il nostro account social su liferay

 

Commenti
Nessun commento. Vuoi essere il primo.