package org.jooby.internal.pac4j; import static org.easymock.EasyMock.expect; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.util.Arrays; import java.util.Collections; import java.util.Optional; import org.jooby.Err; import org.jooby.Mutant; import org.jooby.Request; import org.jooby.Response; import org.jooby.Route; import org.jooby.pac4j.Auth; import org.jooby.pac4j.AuthStore; import org.jooby.test.MockUnit; import org.jooby.test.MockUnit.Block; import org.junit.Test; import org.junit.runner.RunWith; import org.pac4j.core.client.Client; import org.pac4j.core.client.Clients; import org.pac4j.core.client.finder.ClientFinder; import org.pac4j.core.context.WebContext; import org.pac4j.core.credentials.Credentials; import org.pac4j.core.exception.HttpAction; import org.pac4j.core.exception.TechnicalException; import org.pac4j.core.profile.CommonProfile; import org.pac4j.core.profile.UserProfile; import org.pac4j.http.client.direct.ParameterClient; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import javaslang.control.Try; @RunWith(PowerMockRunner.class) @PrepareForTest({AuthFilter.class, Clients.class, ParameterClient.class }) public class AuthFilterTest { private Block webctx = unit -> { Request req = unit.get(Request.class); expect(req.require(WebContext.class)).andReturn(unit.get(WebContext.class)); }; private Block cfinder = unit -> { Request req = unit.get(Request.class); expect(req.require(ClientFinder.class)).andReturn(unit.get(ClientFinder.class)); }; private Block astore = unit -> { Request req = unit.get(Request.class); expect(req.require(AuthStore.class)).andReturn(unit.get(AuthStore.class)); }; private Block clients = unit -> { Clients clients = unit.get(Clients.class); Request req = unit.get(Request.class); expect(req.require(Clients.class)).andReturn(clients); }; private Block chainNext = unit -> { Route.Chain chain = unit.get(Route.Chain.class); chain.next(unit.get(Request.class), unit.get(Response.class)); }; @SuppressWarnings("rawtypes") private <C extends Client> Block findClient(final Class<C> clientType, final String client) { return unit -> { C c = Try.of(() -> unit.get(clientType)) .getOrElse(() -> { C m = unit.powerMock(clientType); //C m = (C) new ParameterClient("token", new SimpleTestUsernamePasswordAuthenticator()); unit.registerMock(clientType, m); return m; }); ClientFinder finder = unit.get(ClientFinder.class); expect(finder.find(unit.get(Clients.class), unit.get(WebContext.class), client)) .andReturn(Arrays.asList(c)); }; } @SuppressWarnings("rawtypes") private <C extends Client> Block findNoClient(final Class<C> clientType, final String client) { return unit -> { ClientFinder finder = unit.get(ClientFinder.class); expect(finder.find(unit.get(Clients.class), unit.get(WebContext.class), client)) .andReturn(Collections.emptyList()); }; } private Block reqAuthID(final String id) { return unit -> { Request req = unit.get(Request.class); expect(req.ifGet(Auth.ID)).andReturn(Optional.ofNullable(id)); }; } @SuppressWarnings("rawtypes") private Block authStore(final String id, final CommonProfile profile) { return unit -> { AuthStore store = unit.get(AuthStore.class); expect(store.get(id)).andReturn(Optional.ofNullable(profile)); }; } @SuppressWarnings("rawtypes") private <C extends Client> Block creds(final Class<C> clientType) { return unit -> { Credentials creds = unit.mock(Credentials.class); unit.registerMock(Credentials.class, creds); WebContext ctx = unit.get(WebContext.class); C client = unit.get(clientType); expect(client.getCredentials(ctx)).andReturn(creds); }; } @SuppressWarnings("rawtypes") private <C extends Client> Block noCreds(final Class<C> clientType) { return unit -> { WebContext ctx = unit.get(WebContext.class); C client = unit.get(clientType); expect(client.getCredentials(ctx)) .andThrow(HttpAction.forbidden("intentional err", ctx)); }; } @SuppressWarnings({"rawtypes", "unchecked" }) private <C extends Client> Block userProfile(final Class<C> clientType, final CommonProfile profile) { return unit -> { Credentials creds = unit.get(Credentials.class); WebContext ctx = unit.get(WebContext.class); C client = unit.get(clientType); expect(client.getUserProfile(creds, ctx)).andReturn(profile); }; } private Block setProfileId(final String id) { return unit -> { Request req = unit.get(Request.class); expect(req.set(Auth.ID, id)).andReturn(req); }; } @SuppressWarnings({"unchecked", "rawtypes" }) private Block setProfile(final CommonProfile profile) { return unit -> { AuthStore store = unit.get(AuthStore.class); store.set(profile); }; } @SuppressWarnings("rawtypes") private Block seed(final Class type, final CommonProfile profile) { return unit -> { Request req = unit.get(Request.class); expect(req.set(type, profile)).andReturn(req); }; } private Block clientName(final String name) { return unit -> { Clients clients = unit.get(Clients.class); expect(clients.getClientNameParameter()).andReturn("client_name"); Mutant client_name = unit.mock(Mutant.class); expect(client_name.value(name)).andReturn(name); Request req = unit.get(Request.class); expect(req.param("client_name")).andReturn(client_name); }; } @Test public void name() throws Exception { String profileId = "123"; CommonProfile profile = new CommonProfile(); profile.setId(profileId); new MockUnit(Request.class, Response.class, Route.Chain.class, WebContext.class, ClientFinder.class, AuthStore.class, Clients.class).run(unit -> { AuthFilter filter = new AuthFilter(ParameterClient.class, CommonProfile.class); assertEquals("ParameterClient", filter.getName()); filter.setName("Basic"); assertEquals("ParameterClient,Basic", filter.getName()); }); } @Test public void handleDirect() throws Exception { String profileId = "123"; CommonProfile profile = new CommonProfile(); profile.setId(profileId); new MockUnit(Request.class, Response.class, Route.Chain.class, WebContext.class, ClientFinder.class, AuthStore.class, Clients.class) .expect(webctx) .expect(cfinder) .expect(astore) .expect(clients) .expect(clientName("ParameterClient")) .expect(findClient(ParameterClient.class, "ParameterClient")) .expect(reqAuthID(profileId)) .expect(reqAuthCNAME(ParameterClient.class)) .expect(authStore(profileId, null)) .expect(creds(ParameterClient.class)) .expect(userProfile(ParameterClient.class, profile)) .expect(setProfileId(profileId)) .expect(setProfile(profile)) .expect(seed(UserProfile.class, profile)) .expect(seed(CommonProfile.class, profile)) .expect(chainNext) .run(unit -> { new AuthFilter(ParameterClient.class, CommonProfile.class) .handle(unit.get(Request.class), unit.get(Response.class), unit.get(Route.Chain.class)); }); } @SuppressWarnings("rawtypes") private Block reqAuthCNAME(final Class<? extends Client> client) { return unit -> { Client c = unit.get(client); expect(c.getName()).andReturn(client.getSimpleName()); Request req = unit.get(Request.class); expect(req.set(Auth.CNAME, client.getSimpleName())).andReturn(req); }; } @Test public void handleDirectNoClient() throws Exception { String profileId = "123"; CommonProfile profile = new CommonProfile(); profile.setId(profileId); new MockUnit(Request.class, Response.class, Route.Chain.class, WebContext.class, ClientFinder.class, AuthStore.class, Clients.class) .expect(webctx) .expect(cfinder) .expect(astore) .expect(clients) .expect(clientName("ParameterClient")) .expect(findNoClient(ParameterClient.class, "ParameterClient")) .expect(findNoClient(ParameterClient.class, "ParameterClient")) .run(unit -> { try { new AuthFilter(ParameterClient.class, CommonProfile.class) .handle(unit.get(Request.class), unit.get(Response.class)); fail("expecting 401"); } catch (Err ex) { assertEquals(401, ex.statusCode()); } }); } @Test(expected = TechnicalException.class) public void handleDirectNoCredentials() throws Exception { String profileId = "123"; CommonProfile profile = new CommonProfile(); profile.setId(profileId); new MockUnit(Request.class, Response.class, Route.Chain.class, WebContext.class, ClientFinder.class, AuthStore.class, Clients.class) .expect(webctx) .expect(cfinder) .expect(astore) .expect(clients) .expect(clientName("ParameterClient")) .expect(findClient(ParameterClient.class, "ParameterClient")) .expect(reqAuthID(profileId)) .expect(authStore(profileId, null)) .expect(noCreds(ParameterClient.class)) .run(unit -> { new AuthFilter(ParameterClient.class, CommonProfile.class) .handle(unit.get(Request.class), unit.get(Response.class), unit.get(Route.Chain.class)); }); } @Test(expected = Err.class) public void handleDirectNoProfile() throws Exception { String profileId = "123"; CommonProfile profile = null; new MockUnit(Request.class, Response.class, Route.Chain.class, WebContext.class, ClientFinder.class, AuthStore.class, Clients.class) .expect(webctx) .expect(cfinder) .expect(astore) .expect(clients) .expect(clientName("ParameterClient")) .expect(findClient(ParameterClient.class, "ParameterClient")) .expect(findClient(ParameterClient.class, "ParameterClient")) .expect(reqAuthID(profileId)) .expect(authStore(profileId, null)) .expect(creds(ParameterClient.class)) .expect(userProfile(ParameterClient.class, profile)) .expect(setProfileId(profileId)) .expect(setProfile(profile)) .run(unit -> { new AuthFilter(ParameterClient.class, CommonProfile.class) .handle(unit.get(Request.class), unit.get(Response.class), unit.get(Route.Chain.class)); }); } }