Unit-testing methods secured with Securesocial ann

2019-03-01 07:34发布

问题:

I'm trying to make some functional tests for my webapplication that is using Play 2.1.4 and Socialsecure. Before using securesocial the tests where pretty straight forward but now im having troubles figuering out how i can make tests on the secured actions.

@Test
public void createNewNote() {
    Result result;
    // Should return bad request if no data is given
    result = callAction(
            controllers.routes.ref.Notes.newNote(),
            fakeRequest().withFormUrlEncodedBody(
                    ImmutableMap.of("title", "", "text",
                            "")));
    assertThat(status(result)).isEqualTo(BAD_REQUEST);

    result = callAction(
            controllers.routes.ref.Notes.newNote(),
            fakeRequest().withFormUrlEncodedBody(
                    ImmutableMap.of("title", "My note title", "text",
                            "My note content")));

    // Should return redirect status if successful
    assertThat(status(result)).isEqualTo(SEE_OTHER);
    assertThat(redirectLocation(result)).isEqualTo("/notes");

    Note newNote = Note.find.where().eq("title", "My note title")
            .findUnique();

    // Should be saved to DB
    assertNotNull(newNote);
    assertEquals("My note title", newNote.title);
    assertEquals("My note content", newNote.text);
}

As of right now i got a user in the test yml file:

- !!models.User
id: 1234567890
username: Pingu
provider: Twitter
firstName: Pingu
lastName: Pingusson
email: pingu@note.com
password: password

My user is pretty straight forward...:

@Table(
    uniqueConstraints=
        @UniqueConstraint(columnNames={"username"}))
@Entity
public class User extends Model {

    private static final long serialVersionUID = 1L;

@Id
public String id;

public String provider;

public String firstName;

public String lastName;

public String email;

public String password;

@MinLength(5)
@MaxLength(20)
public String username;

public static Finder<String, User> find = new Finder<String, User>(
        String.class, User.class);

public static User findById(String id) {
    return find.where().eq("id", id).findUnique();
}
public static User findByEmail(String email) {
    return find.where().eq("email", email).findUnique();
}
@Override
public String toString() {
    return this.id + " - " + this.firstName;
}

}

and the UserService:

public class UserService extends BaseUserService {

public UserService(Application application) {
    super(application);
}

@Override
public void doDeleteExpiredTokens() {
    if (Logger.isDebugEnabled()) {
        Logger.debug("deleteExpiredTokens...");
    }
    List<LocalToken> list = LocalToken.find.where().lt("expireAt", new DateTime().toString()).findList();
    for(LocalToken localToken : list) {
        localToken.delete();
    }
}

@Override
public void doDeleteToken(String uuid) {
    if (Logger.isDebugEnabled()) {
        Logger.debug("deleteToken...");
        Logger.debug(String.format("uuid = %s", uuid));
    }
    LocalToken localToken = LocalToken.find.byId(uuid);
    if(localToken != null) {
        localToken.delete();
    }
}

@Override
//public Identity doFind(UserId userId) {
public Identity doFind(IdentityId identityId){
    if (Logger.isDebugEnabled()) {
        Logger.debug(String.format("finding by Id = %s", identityId.userId()));

    }

    User localUser = User.find.byId(identityId.userId());
    Logger.debug(String.format("localUser = " + localUser));
    if(localUser == null) return null;
    SocialUser socialUser = new SocialUser(new IdentityId(localUser.id, localUser.provider),    
        localUser.firstName, 
        localUser.lastName, 
        String.format("%s %s", localUser.firstName, localUser.lastName),
        Option.apply(localUser.email), 
        null, 
        new AuthenticationMethod("userPassword"),
        null, 
        null, 
        Some.apply(new PasswordInfo("bcrypt", localUser.password, null))
    );  
    if (Logger.isDebugEnabled()) {
        Logger.debug(String.format("socialUser = %s", socialUser));
    }
    return socialUser;
}


@Override
public Identity doFindByEmailAndProvider(String email, String providerId) {
    List<User> list = User.find.where().eq("email", email).eq("provider", providerId).findList();
    if(list.size() != 1){
        Logger.debug("found a null in findByEmailAndProvider...");
        return null;
    }
    User localUser = list.get(0);
    SocialUser socialUser = 
            new SocialUser(new IdentityId(localUser.email, localUser.provider),
                    localUser.firstName, 
                    localUser.lastName, 
                    String.format("%s %s", localUser.firstName, localUser.lastName),
                    Option.apply(localUser.email), 
                    null, 
                    new AuthenticationMethod("userPassword"),
                    null, 
                    null, 
                    Some.apply(new PasswordInfo("bcrypt", localUser.password, null))
               );  
    return socialUser;
}

@Override
public Token doFindToken(String token) {
    if (Logger.isDebugEnabled()) {
        Logger.debug("findToken...");
        Logger.debug(String.format("token = %s", token));
    }
    LocalToken localToken = LocalToken.find.byId(token);
    if(localToken == null) return null;
    Token result = new Token();
    result.uuid = localToken.uuid;
    result.creationTime = new DateTime(localToken.createdAt);
    result.email = localToken.email;
    result.expirationTime = new DateTime(localToken.expireAt);
    result.isSignUp = localToken.isSignUp;
    if (Logger.isDebugEnabled()) {
        Logger.debug(String.format("foundToken = %s", result));
    }
    return result;
}

@Override
public Identity doSave(Identity user) {
    if (Logger.isDebugEnabled()) {
        Logger.debug("save...!_!");
        Logger.debug(String.format("user = %s", user));
    }
    User localUser = null;
    localUser = User.find.byId(user.identityId().userId());
    Logger.debug("id = " + user.identityId().userId());
    Logger.debug("provider = " + user.identityId().providerId());
    Logger.debug("firstName = " + user.firstName());
    Logger.debug("lastName = " + user.lastName());
    Logger.debug(user.fullName() + "");
    Logger.debug("email = " + user.email());
    Logger.debug(user.email().getClass() + "");

    if (localUser == null) {
        Logger.debug("adding new...");
        localUser = new User();
        localUser.id = user.identityId().userId();
        localUser.provider = user.identityId().providerId();
        localUser.firstName = user.firstName();
        localUser.lastName = user.lastName();

        //Temporary solution for twitter which does not have email in OAuth answer
        if(!(user.email().toString()).equals("None")){
            localUser.email = user.email().get();
        }
        if(!(user.passwordInfo() + "").equals("None")){
            localUser.password = user.passwordInfo().get().password();
        }
        localUser.save();
    } else {
        Logger.debug("existing one...");
        localUser.id = user.identityId().userId();
        localUser.provider = user.identityId().providerId();
        localUser.firstName = user.firstName();
        localUser.lastName = user.lastName();

        //Temporary solution for twitter which does not have email in OAuth answer
        if(!(user.email().toString()).equals("None")){
            localUser.email = user.email().get();
        }
        if(!(user.passwordInfo() + "").equals("None")){
            localUser.password = user.passwordInfo().get().password();
        }
        localUser.update();
    }
    return user;
}

@Override
public void doSave(Token token) {
    LocalToken localToken = new LocalToken();
    localToken.uuid = token.uuid;
    localToken.email = token.email;
    try {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        localToken.createdAt = df.parse(token.creationTime.toString("yyyy-MM-dd HH:mm:ss"));
        localToken.expireAt = df.parse(token.expirationTime.toString("yyyy-MM-dd HH:mm:ss"));
    } catch (ParseException e) {
        Logger.error("UserService.doSave(): ", e);
    }
    localToken.isSignUp = token.isSignUp;
    localToken.save();
}

}

As of my understanding i should in someway set the session so the user is logged in by using the .withsession method on the fakerequest and maybe also set some value on the serverside.

Tried searching the web for examples using securesocial and play but found no tests at all.

How can i login in my user so i can preform the tests?

Best regards Rawa

回答1:

Thanks to David Weinbergs comment i was able to solve this after some trail and error. (:

I started out my LocalUser implementation from this reply: https://stackoverflow.com/a/18589402/1724097

This is how i solved it:

To make unit tests i created a local user in the database, using the test-data.yml file:

- !!models.LocalUser
    id: 1234567890
    username: Username
    provider: userpass
    firstName: firstName
    lastName: lastName
    email: user@example.com
    #hash for "password"
    password: $2a$10$.VE.rwJFMblRv2HIqhZM5.CiqzYOhhJyLYrKpMmwXar6Vp58U7flW 

Then i made a test utils class that create my fakeCookie.

import models.LocalUser;
import play.Logger;
import securesocial.core.Authenticator;
import securesocial.core.IdentityId;
import securesocial.core.SocialUser;
import securesocial.core.PasswordInfo;
import scala.Some;
import securesocial.core.AuthenticationMethod;
import scala.Option;
import scala.util.Right;
import scala.util.Either;
import play.mvc.Http.Cookie;

public class Utils {


    public static Cookie fakeCookie(String user){

        LocalUser localUser = LocalUser.findByEmail(user);
        Logger.debug("Username: " + localUser.username +" - ID: " + localUser.id);

        SocialUser socialUser = new SocialUser(new IdentityId(localUser.id, localUser.provider),    
            localUser.firstName, 
            localUser.lastName, 
            String.format("%s %s", localUser.firstName, localUser.lastName),
            Option.apply(localUser.email), 
            null, 
            new AuthenticationMethod("userPassword"),
            null, 
            null, 
            Some.apply(new PasswordInfo("bcrypt", localUser.password, null))
        );  

        Either either = Authenticator.create(socialUser);
        Authenticator auth = (Authenticator) either.right().get();
        play.api.mvc.Cookie scalaCookie = auth.toCookie();


        //debug loggig
        Logger.debug("Cookie data:");
        Logger.debug("Name: " + "Value: " + auth.cookieName() + " | Class: " + auth.cookieName().getClass() + " | Should be type: " + "java.lang.String");
        Logger.debug("Value: " + "Value: " + scalaCookie.value() + " | Class: " + scalaCookie.value().getClass() + " | Should be type: " + "java.lang.String");
        Logger.debug("MaxAge: " + "Value: " + scalaCookie.maxAge() + " | Class: " + scalaCookie.maxAge().getClass() + " | Should be type: " + "int");
        Logger.debug("Path: " + "Value: " + scalaCookie.path() + " | Class: " + scalaCookie.path().getClass() + " | Should be type: " + "java.lang.String");
        Logger.debug("Domain: " + "Value: " + scalaCookie.domain() + " | Class: " + auth.cookieDomain().getClass() + " | Should be type: " + "java.lang.String");
        Logger.debug("Secure: " + "Value: " + auth.cookieSecure() + " | Class: " + "Boolean" + " | Should be type: " + "boolean");
        Logger.debug("HttpOnly: " + "Value: " + auth.cookieHttpOnly() + " | Class: " + "Boolean" + " | Should be type: " + "boolean");

        // secureSocial doesnt seem to set a maxAge or Domain so i set them myself.
        Cookie fakeCookie = new Cookie(auth.cookieName(), scalaCookie.value(), 120, scalaCookie.path(), "None", auth.cookieSecure(), auth.cookieHttpOnly());
        return fakeCookie;
    }
}

And then i simply use my cookie to in the fakeRequest so im logged in:

Cookie cookie = Utils.fakeCookie("user@example.com");

Result result = callAction(
        controllers.routes.ref.yourSampleClass.yourSecuredFucntion(),
        fakeRequest().withFormUrlEncodedBody(
                ImmutableMap.of("Value", "Some input value")).withCookies(cookie));

// Should return redirect status if successful
assertThat(status(result)).isEqualTo(SEE_OTHER);
assertThat(redirectLocation(result)).isEqualTo("/yourWantedResult");

Hope this helps others!