Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
Copyright (C) 2009 eXo Platform SAS. This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this software; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 
 
 package org.exoplatform.web.security.security;
 
 
 import java.util.Date;
 import java.util.List;


Created by The eXo Platform SAS Author : liem.nguyen ncliam@gmail.com Jun 5, 2009

On 2013-01-02 the followig was added by ppalaga@redhat.com:

  • Passwords encrypted symmetrically before they are stored. The functionaliy was taken from https://github.com/exoplatform/exogtn/commit/5ef8b0fa2d639f4d834444468426dfb2c8485ae9 with minor modifications. See codec
  • The tokens are not stored in plain text, but intead only their salted hash is stored. See saltedHashService. To enable this, the following was done:
    • The structure of the underlying JCR store was changed from
       autologin
       |- plain-token1 user="user1" password="***" expiration="..."
       |- plain-token2 user="user2" password="***" expiration="..."
       `- ...
       
      to
       autologin
       |- user1
       |  |- plain-token1 user="user1" password="***" expiration="..."
       |  |- plain-token2 user="user1" password="***" expiration="..."
       |  `- ...
       |- user2
       |  |- plain-token3 user="user2" password="***" expiration="..."
       |  |- plain-token4 user="user2" password="***" expiration="..."
       |  `- ...
       `- ...
       
    • The value of the token was changed from "rememberme" + randomString to userName + '.' + randomString

It should be considered in the future if the password field can be removed altogether from TokenEntry.

 
 public class CookieTokenService extends AbstractTokenService<GateInTokenString> {

    
.
 
     public static final String LIFECYCLE_NAME = "lifecycle-name";
     public static final String HASH_SERVICE_INIT_PARAM = "hash.service";

    
.
    private ChromatticLifeCycle chromatticLifeCycle;

    
.
    private String lifecycleName = "autologin";

    
org.exoplatform.web.security.codec.AbstractCodec used to symmetrically encrypt passwords before storing them.
    private AbstractCodec codec;
    private final Logger log = LoggerFactory.getLogger(CookieTokenService.class);
    public CookieTokenService(InitParams initParamsChromatticManager chromatticManagerCodecInitializer codecInitializer)
            throws TokenServiceInitializationException {
        super(initParams);
        List<?> serviceConfig = initParams.getValuesParam().getValues();
        if (serviceConfig.size() > 3) {
             = (StringserviceConfig.get(3);
        }
        this. = chromatticManager.getLifeCycle();
        ObjectParameter hashServiceParam = initParams.getObjectParam();
        if (hashServiceParam == null || hashServiceParam.getObject() == null) {
            /* the default */
             = new JCASaltedHashService();
        } else {
             = (SaltedHashServicehashServiceParam.getObject();
        }
        this. = codecInitializer.getCodec();
    }
    /*
     * (non-Javadoc)
     *
     * @see org.exoplatform.web.security.security.AbstractTokenService#start()
     */
    @Override
    public void start() {
        /* clean the legacy tokens */
        new TokenTask<Void>() {
            @Override
            protected Void execute(SessionContext context) {
                ChromatticSession session = context.getSession();
                TokenContainer container = session.findByPath(TokenContainer.class);
                if (container != null) {
                    /* if the container does not exist, it makes no sense to clean the legacy tokens */
                    container.cleanLegacyTokens();
                } else {
                    session.insert(TokenContainer.class);
                }
                return null;
            }
        super.start();
    }
    public String createToken(final Credentials credentials) {
        if ( < 0) {
            throw new IllegalArgumentException();
        }
        if (credentials == null) {
            throw new NullPointerException();
        }
        return new TokenTask<String>() {
            @Override
            protected String execute(SessionContext context) {
                String cookieTokenString = null;
                TokenContainer tokenContainer = getTokenContainer();
                while (cookieTokenString == null) {
                    String randomString = nextTokenId();
                    String id = nextRandom();
                    cookieTokenString = new CookieToken(idrandomString).toString();
                    String hashedRandomString = hashToken(randomString);
                    long expirationTimeMillis = System.currentTimeMillis() + ;
                    /* the symmetric encryption happens here */
                    String encryptedPassword = .encode(credentials.getPassword());
                    Credentials encodedCredentials = new Credentials(credentials.getUsername(), encryptedPassword);
                    try {
                        tokenContainer.saveToken(context.getSession(), idhashedRandomStringencodedCredentialsnew Date(expirationTimeMillis));
                    } catch (TokenExistsException e) {
                        cookieTokenString = null;
                    }
                }
                return cookieTokenString;
            }
    }
    @Override
    protected String nextTokenId() {
        return nextRandom();
    }
    @Override
    public GateInToken getToken(String cookieTokenString) {
        CookieToken token = null;
        try {
            token = new CookieToken(cookieTokenString);
            return new RemovableGetTokenTask(tokenfalse).executeWith();
        } catch (TokenParseException e) {
            .warn("Could not parse cookie token:"e.getMessage());
        }
        return null;
    }
    @Override
    public GateInToken deleteToken(String cookieTokenString) {
        CookieToken token = null;
        try {
            token = new CookieToken(cookieTokenString);
            return new RemovableGetTokenTask(tokentrue).executeWith();
        } catch (TokenParseException e) {
            .warn("Could not parse cookie token:"e.getMessage());
        }
        return null;
    }

    
The UI should offer a way to delete all existing tokens of the current user.

Parameters:
user
    public void deleteTokensOfUser(final String user) {
        new TokenTask<Void>() {
            @Override
            protected Void execute(SessionContext context) {
                QueryResult<TokenEntryresult = findTokensOfUser(user);
                while (result.hasNext()) {
                    TokenEntry en = result.next();
                    en.remove();
                }
                return null;
            }
    }

    
Removes all tokens stored in the TokenContainer.
    public void deleteAll() {
        new TokenTask<Void>() {
            @Override
            protected Void execute(SessionContext context) {
                getTokenContainer().removeAll();
                return null;
            }
    }
    @Override
    public void cleanExpiredTokens() {
        new TokenTask<Void>() {
            @Override
            protected Void execute(SessionContext context) {
                getTokenContainer().cleanExpiredTokens();
                return null;
            }
    }
    @Override
    public long size() {
        return new TokenTask<Long>() {
            @Override
            protected Long execute(SessionContext context) {
                return (longgetTokenContainer().size();
            }
    }
    @Override
    protected String decodeKey(String stringKey) {
        return stringKey;
    }
    private String hashToken(String tokenId) {
        if ( != null) {
            try {
                return .getSaltedHash(tokenId);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        } else {
            /* no hash if saltedHashService is null */
            return tokenId;
        }
    }

    
Wraps token store logic conveniently.

Parameters:
<V> the return type
    private abstract class TokenTask<V> extends ContextualTask<V> {
        protected final TokenContainer getTokenContainer() {
            SessionContext ctx = .getContext();
            ChromatticSession session = ctx.getSession();
            return session.findByPath(TokenContainer.class);
        }
        protected final <A> A getMixin(Object oClass<A> type) {
            SessionContext ctx = .getContext();
            ChromatticSession session = ctx.getSession();
            return session.getEmbedded(otype);
        }
        protected final QueryResult<TokenEntryfindTokensOfUser(String user) {
            SessionContext ctx = .getContext();
            ChromatticSession session = ctx.getSession();
            TokenContainer tokenContainer = getTokenContainer();
            String statement = new StringBuilder(128).append("jcr:path LIKE '").append(session.getPath(tokenContainer))
                    .append("/%'").append(" AND username='").append(Utils.queryEscape(user)).append("'").toString();
            return session.createQueryBuilder(TokenEntry.class).where(statement).get().objects();
        }
    }
    private class RemovableGetTokenTask extends TokenTask<GateInToken> {
        private final CookieToken token;
        private final boolean remove;

        

Parameters:
token
        public RemovableGetTokenTask(CookieToken tokenboolean remove) {
            super();
            this. = token;
            this. = remove;
        }
        @Override
        protected GateInToken execute(SessionContext context) {
            TokenEntry en = getTokenContainer().getTokens().get(.getId());
            if (en != null) {
                HashedToken hashedToken = getMixin(enHashedToken.class);
                if (hashedToken != null && hashedToken.getHashedToken() != null) {
                    try {
                        if (.validate(.getRandomString(), hashedToken.getHashedToken())) {
                            GateInToken encryptedToken = en.getToken();
                            Credentials encryptedCredentials = encryptedToken.getPayload();
                            Credentials decryptedCredentials = new Credentials(encryptedCredentials.getUsername(),
                            .decode(encryptedCredentials.getPassword()));
                            if () {
                                en.remove();
                            }
                            return new GateInToken(encryptedToken.getExpirationTimeMillis(), decryptedCredentials);
                        }
                    } catch (SaltedHashException e) {
                        .warn("Could not validate cookie token against its salted hash."e);
                    }
                }
            }
            return null;
        }
    }
New to GrepCode? Check out our FAQ X