Search in sources :

Example 1 with DeviceRepresentation

use of org.keycloak.representations.account.DeviceRepresentation in project keycloak by keycloak.

the class DeviceActivityManager method getDeviceFromUserAgent.

private static DeviceRepresentation getDeviceFromUserAgent(KeycloakSession session) {
    KeycloakContext context = session.getContext();
    if (context.getRequestHeaders() == null) {
        return null;
    }
    String userAgent = context.getRequestHeaders().getHeaderString(HttpHeaders.USER_AGENT);
    if (userAgent == null) {
        return null;
    }
    if (userAgent.length() > USER_AGENT_MAX_LENGTH) {
        logger.warn("Ignoring User-Agent header. Length is above the permitted: " + USER_AGENT_MAX_LENGTH);
        return null;
    }
    DeviceRepresentation current;
    try {
        Client client = UA_PARSER.parse(userAgent);
        current = new DeviceRepresentation();
        current.setDevice(client.device.family);
        String browserVersion = client.userAgent.major;
        if (client.userAgent.minor != null) {
            browserVersion += "." + client.userAgent.minor;
        }
        if (client.userAgent.patch != null) {
            browserVersion += "." + client.userAgent.patch;
        }
        if (browserVersion == null) {
            browserVersion = DeviceRepresentation.UNKNOWN;
        }
        current.setBrowser(client.userAgent.family, browserVersion);
        current.setOs(client.os.family);
        String osVersion = client.os.major;
        if (client.os.minor != null) {
            osVersion += "." + client.os.minor;
        }
        if (client.os.patch != null) {
            osVersion += "." + client.os.patch;
        }
        if (client.os.patchMinor != null) {
            osVersion += "." + client.os.patchMinor;
        }
        current.setOsVersion(osVersion);
        current.setIpAddress(context.getConnection().getRemoteAddr());
        current.setMobile(userAgent.toLowerCase().contains("mobile"));
    } catch (Exception cause) {
        logger.error("Failed to create device info from user agent header", cause);
        return null;
    }
    return current;
}
Also used : DeviceRepresentation(org.keycloak.representations.account.DeviceRepresentation) KeycloakContext(org.keycloak.models.KeycloakContext) Client(ua_parser.Client) IOException(java.io.IOException)

Example 2 with DeviceRepresentation

use of org.keycloak.representations.account.DeviceRepresentation in project keycloak by keycloak.

the class SessionRestServiceTest method testGetDevicesSessions.

@Test
public void testGetDevicesSessions() throws Exception {
    ContainerAssume.assumeAuthServerUndertow();
    assumeTrue("Browser must be htmlunit. Otherwise we are not able to set desired BrowserHeaders", System.getProperty("browser").equals("htmlUnit"));
    WebDriver firstBrowser = oauth.getDriver();
    // first browser authenticates from Fedora
    oauth.setBrowserHeader("User-Agent", "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1");
    codeGrant("public-client-0");
    List<DeviceRepresentation> devices = getDevicesOtherThanOther();
    assertEquals("Should have a single device", 1, devices.size());
    List<DeviceRepresentation> fedoraDevices = devices.stream().filter(deviceRepresentation -> "Fedora".equals(deviceRepresentation.getOs())).collect(Collectors.toList());
    assertEquals("Should have a single Fedora device", 1, fedoraDevices.size());
    fedoraDevices.stream().forEach(device -> {
        List<SessionRepresentation> sessions = device.getSessions();
        assertEquals(1, sessions.size());
        assertThat(sessions, Matchers.hasItem(Matchers.hasProperty("browser", Matchers.is("Firefox/15.0.1"))));
    });
    // second browser authenticates from Windows
    oauth.setDriver(secondBrowser);
    oauth.setBrowserHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Gecko/20100101 Firefox/15.0.1");
    codeGrant("public-client-0");
    devices = getDevicesOtherThanOther();
    // should have two devices
    assertEquals("Should have two devices", 2, devices.size());
    fedoraDevices = devices.stream().filter(deviceRepresentation -> "Fedora".equals(deviceRepresentation.getOs())).collect(Collectors.toList());
    assertEquals(1, fedoraDevices.size());
    List<DeviceRepresentation> windowsDevices = devices.stream().filter(deviceRepresentation -> "Windows".equals(deviceRepresentation.getOs())).collect(Collectors.toList());
    assertEquals(1, windowsDevices.size());
    windowsDevices.stream().forEach(device -> {
        List<SessionRepresentation> sessions = device.getSessions();
        assertEquals(1, sessions.size());
        assertThat(sessions, Matchers.hasItem(Matchers.hasProperty("browser", Matchers.is("Firefox/15.0.1"))));
    });
    // first browser authenticates from Windows using Edge
    oauth.setDriver(firstBrowser);
    oauth.setBrowserHeader("User-Agent", "Mozilla/5.0 (Windows Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36 Edge/12.0");
    codeGrant("public-client-0");
    // second browser authenticates from Windows using Firefox
    oauth.setDriver(secondBrowser);
    oauth.setBrowserHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Gecko/20100101 Firefox/15.0.1");
    codeGrant("public-client-0");
    // third browser authenticates from Windows using Safari
    oauth.setDriver(thirdBrowser);
    oauth.setBrowserHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Version/11.0 Safari/603.1.30");
    oauth.setBrowserHeader("X-Forwarded-For", "192.168.10.3");
    OAuthClient.AccessTokenResponse tokenResponse = codeGrant("public-client-0");
    devices = getDevicesOtherThanOther(tokenResponse.getAccessToken());
    assertEquals("Should have a single device because all browsers (and sessions) are from the same platform (OS + OS version)", 1, devices.size());
    windowsDevices = devices.stream().filter(device -> "Windows".equals(device.getOs())).collect(Collectors.toList());
    assertEquals(1, windowsDevices.size());
    windowsDevices.stream().forEach(device -> {
        List<SessionRepresentation> sessions = device.getSessions();
        assertEquals(3, sessions.size());
        assertEquals(1, sessions.stream().filter(rep -> rep.getIpAddress().equals("127.0.0.1") && rep.getBrowser().equals("Firefox/15.0.1") && rep.getCurrent() == null).count());
        assertEquals(1, sessions.stream().filter(rep -> rep.getIpAddress().equals("127.0.0.1") && rep.getBrowser().equals("Edge/12.0") && rep.getCurrent() == null).count());
        assertEquals(1, sessions.stream().filter(rep -> rep.getIpAddress().equals("192.168.10.3") && rep.getBrowser().equals("Safari/11.0") && rep.getCurrent()).count());
    });
    // third browser authenticates from Windows using a different Windows version
    oauth.setDriver(thirdBrowser);
    oauth.setBrowserHeader("User-Agent", "Mozilla/5.0 (Windows 7) AppleWebKit/537.36 (KHTML, like Gecko) Version/11.0 Safari/603.1.30");
    oauth.setBrowserHeader("X-Forwarded-For", "192.168.10.3");
    codeGrant("public-client-0");
    devices = getDevicesOtherThanOther();
    windowsDevices = devices.stream().filter(device -> "Windows".equals(device.getOs())).collect(Collectors.toList());
    assertEquals("Should have two devices for two distinct Windows versions", 2, devices.size());
    assertEquals(2, windowsDevices.size());
    oauth.setDriver(firstBrowser);
    oauth.setBrowserHeader("User-Agent", "Mozilla/5.0 (iPhone; CPU iPhone OS 5_1_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9B206 Safari/7534.48.3");
    codeGrant("public-client-0");
    oauth.setDriver(secondBrowser);
    oauth.setBrowserHeader("User-Agent", "Mozilla/5.0 (X11; Fedora; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1");
    codeGrant("public-client-0");
    devices = getDevicesOtherThanOther();
    assertEquals("Should have 3 devices", 3, devices.size());
    windowsDevices = devices.stream().filter(device -> "Windows".equals(device.getOs())).collect(Collectors.toList());
    assertEquals(1, windowsDevices.size());
    fedoraDevices = devices.stream().filter(deviceRepresentation -> "Fedora".equals(deviceRepresentation.getOs())).collect(Collectors.toList());
    assertEquals(1, fedoraDevices.size());
    List<DeviceRepresentation> iphoneDevices = devices.stream().filter(device -> "iOS".equals(device.getOs()) && "iPhone".equals(device.getDevice())).collect(Collectors.toList());
    assertEquals(1, iphoneDevices.size());
    iphoneDevices.stream().forEach(device -> {
        assertTrue(device.isMobile());
        List<SessionRepresentation> sessions = device.getSessions();
        assertEquals(1, sessions.size());
        assertEquals(1, sessions.stream().filter(rep -> rep.getBrowser().equals("Mobile Safari/5.1")).count());
    });
}
Also used : WebDriver(org.openqa.selenium.WebDriver) ThirdBrowser(org.keycloak.testsuite.util.ThirdBrowser) AuthServerContainerExclude(org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude) SecondBrowser(org.keycloak.testsuite.util.SecondBrowser) WebDriver(org.openqa.selenium.WebDriver) DeviceRepresentation(org.keycloak.representations.account.DeviceRepresentation) ContainerAssume(org.keycloak.testsuite.util.ContainerAssume) Assert.assertThat(org.junit.Assert.assertThat) OAuthClient(org.keycloak.testsuite.util.OAuthClient) SimpleHttp(org.keycloak.broker.provider.util.SimpleHttp) Drone(org.jboss.arquillian.drone.api.annotation.Drone) TypeReference(com.fasterxml.jackson.core.type.TypeReference) AuthServer(org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer) SessionRepresentation(org.keycloak.representations.account.SessionRepresentation) TokenUtil(org.keycloak.testsuite.util.TokenUtil) Assert.assertNotNull(org.junit.Assert.assertNotNull) Assert.assertTrue(org.junit.Assert.assertTrue) Matchers(org.hamcrest.Matchers) IOException(java.io.IOException) Test(org.junit.Test) Collectors(java.util.stream.Collectors) RealmRepresentation(org.keycloak.representations.idm.RealmRepresentation) List(java.util.List) Matchers.equalTo(org.hamcrest.Matchers.equalTo) ClientRepresentation(org.keycloak.representations.account.ClientRepresentation) ClientBuilder(org.keycloak.testsuite.util.ClientBuilder) Assume.assumeTrue(org.junit.Assume.assumeTrue) Matchers.anyOf(org.hamcrest.Matchers.anyOf) Assert.assertEquals(org.junit.Assert.assertEquals) OAuth2Constants(org.keycloak.OAuth2Constants) DeviceRepresentation(org.keycloak.representations.account.DeviceRepresentation) OAuthClient(org.keycloak.testsuite.util.OAuthClient) SessionRepresentation(org.keycloak.representations.account.SessionRepresentation) Test(org.junit.Test)

Example 3 with DeviceRepresentation

use of org.keycloak.representations.account.DeviceRepresentation in project keycloak by keycloak.

the class SessionRestServiceTest method testGetDevicesResponse.

@Test
@AuthServerContainerExclude(AuthServer.REMOTE)
public void testGetDevicesResponse() throws Exception {
    assumeTrue("Browser must be htmlunit. Otherwise we are not able to set desired BrowserHeaders", System.getProperty("browser").equals("htmlUnit"));
    oauth.setBrowserHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0) Gecko/20100101 Firefox/15.0.1");
    OAuthClient.AccessTokenResponse tokenResponse = codeGrant("public-client-0");
    joinSsoSession("public-client-1");
    List<DeviceRepresentation> devices = getDevicesOtherThanOther(tokenResponse.getAccessToken());
    assertEquals("Should have a single device", 1, devices.size());
    DeviceRepresentation device = devices.get(0);
    assertTrue(device.getCurrent());
    assertEquals("Windows", device.getOs());
    assertEquals("10", device.getOsVersion());
    assertEquals("Other", device.getDevice());
    List<SessionRepresentation> sessions = device.getSessions();
    assertEquals(1, sessions.size());
    SessionRepresentation session = sessions.get(0);
    assertEquals("127.0.0.1", session.getIpAddress());
    assertTrue(device.getLastAccess() == session.getLastAccess());
    List<ClientRepresentation> clients = session.getClients();
    assertEquals(2, clients.size());
    assertThat(session.getClients(), Matchers.hasItem(Matchers.hasProperty("clientId", anyOf(Matchers.is("public-client-0"), Matchers.is("public-client-1")))));
    assertThat(session.getClients(), Matchers.hasItem(Matchers.hasProperty("clientName", anyOf(Matchers.is("Public Client 0"), Matchers.is("Public Client 1")))));
}
Also used : DeviceRepresentation(org.keycloak.representations.account.DeviceRepresentation) OAuthClient(org.keycloak.testsuite.util.OAuthClient) SessionRepresentation(org.keycloak.representations.account.SessionRepresentation) ClientRepresentation(org.keycloak.representations.account.ClientRepresentation) AuthServerContainerExclude(org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude) Test(org.junit.Test)

Example 4 with DeviceRepresentation

use of org.keycloak.representations.account.DeviceRepresentation in project keycloak by keycloak.

the class SessionRestServiceTest method testNullOrEmptyUserAgent.

@Test
@AuthServerContainerExclude(AuthServer.REMOTE)
public void testNullOrEmptyUserAgent() throws Exception {
    assumeTrue("Browser must be htmlunit. Otherwise we are not able to set desired BrowserHeaders", System.getProperty("browser").equals("htmlUnit"));
    oauth.setBrowserHeader("User-Agent", null);
    OAuthClient.AccessTokenResponse tokenResponse = codeGrant("public-client-0");
    List<DeviceRepresentation> devices = queryDevices(tokenResponse.getAccessToken());
    assertEquals("Should have a single device", 1, devices.size());
    DeviceRepresentation device = devices.get(0);
    assertTrue(device.getCurrent());
    assertEquals("Other", device.getOs());
    assertEquals("Other", device.getDevice());
    List<SessionRepresentation> sessions = device.getSessions();
    assertEquals(1, sessions.size());
    SessionRepresentation session = sessions.get(0);
    assertEquals("127.0.0.1", session.getIpAddress());
    assertEquals(device.getLastAccess(), session.getLastAccess());
    assertEquals(1, session.getClients().size());
}
Also used : DeviceRepresentation(org.keycloak.representations.account.DeviceRepresentation) OAuthClient(org.keycloak.testsuite.util.OAuthClient) SessionRepresentation(org.keycloak.representations.account.SessionRepresentation) AuthServerContainerExclude(org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude) Test(org.junit.Test)

Example 5 with DeviceRepresentation

use of org.keycloak.representations.account.DeviceRepresentation in project keycloak by keycloak.

the class SessionResource method getAttachedDevice.

private DeviceRepresentation getAttachedDevice(UserSessionModel s) {
    DeviceRepresentation device = DeviceActivityManager.getCurrentDevice(s);
    if (device == null) {
        device = DeviceRepresentation.unknown();
        device.setIpAddress(s.getIpAddress());
    }
    return device;
}
Also used : DeviceRepresentation(org.keycloak.representations.account.DeviceRepresentation)

Aggregations

DeviceRepresentation (org.keycloak.representations.account.DeviceRepresentation)6 Test (org.junit.Test)3 SessionRepresentation (org.keycloak.representations.account.SessionRepresentation)3 AuthServerContainerExclude (org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude)3 OAuthClient (org.keycloak.testsuite.util.OAuthClient)3 IOException (java.io.IOException)2 ClientRepresentation (org.keycloak.representations.account.ClientRepresentation)2 TypeReference (com.fasterxml.jackson.core.type.TypeReference)1 HashMap (java.util.HashMap)1 List (java.util.List)1 Collectors (java.util.stream.Collectors)1 GET (javax.ws.rs.GET)1 Path (javax.ws.rs.Path)1 Produces (javax.ws.rs.Produces)1 Matchers (org.hamcrest.Matchers)1 Matchers.anyOf (org.hamcrest.Matchers.anyOf)1 Matchers.equalTo (org.hamcrest.Matchers.equalTo)1 Drone (org.jboss.arquillian.drone.api.annotation.Drone)1 NoCache (org.jboss.resteasy.annotations.cache.NoCache)1 Assert.assertEquals (org.junit.Assert.assertEquals)1