Skip to content

[KEYCLOAK-7416] Added code to store device information from the user-agent header - #6127

Closed
abstractj wants to merge 1 commit into
keycloak:masterfrom
abstractj:KEYCLOAK-7416
Closed

[KEYCLOAK-7416] Added code to store device information from the user-agent header#6127
abstractj wants to merge 1 commit into
keycloak:masterfrom
abstractj:KEYCLOAK-7416

Conversation

@abstractj

Copy link
Copy Markdown
Contributor

No description provided.

douglaspalmer
douglaspalmer previously approved these changes Jun 27, 2019
@abstractj
abstractj requested review from hmlnarik and mposolda June 27, 2019 18:28
@abstractj

Copy link
Copy Markdown
Contributor Author

@mposolda @hmlnarik I just did a rebase (nothing has changed since Marek's approval) of #5582 and @douglaspalmer already reviewed and approved it. He also handled uap-java parser and seems we are all set.

Only to make sure we're on the same page and has been a while, could you please take and check if there are more considerations around it?

@abstractj
abstractj marked this pull request as ready for review June 27, 2019 18:31

@hmlnarik hmlnarik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why there is a need to change the UserSessionModel? I believe the device info should be only placed there as a note, just the same as other notes, and used only when needed. This would limit the number of changes in the PR

@@ -235,6 +236,14 @@ public void testGetSessions() throws IOException {
List<SessionRepresentation> sessions = SimpleHttp.doGet(getAccountUrl("sessions"), httpClient).auth(tokenUtil.getToken()).asJson(new TypeReference<List<SessionRepresentation>>() {});

assertEquals(1, sessions.size());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Implement DeviceInfo.equals and use assertThat(sessions, contains(expectedDeviceInfo))

String browser = deviceInfo.getBrowser();
String os = deviceInfo.getOs();

assertEquals("Other", device);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use some other device info that uses explictly set values for some device (this needs to be done by manipulating the HTTP headers before GET is performed.

}

public String toString() {
StringBuilder builder = new StringBuilder();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. : needs to be escaped inside values and decoded in create
  2. Feel free to use:
builder.append(device)
  .append(':')
  .append(browser)
...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or other alternative can be to use other very strange delimiter like @@ when there is no chance of having the delimiter in the values and hence no escaping needed.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regardless of the actual separator shape, it needs to be escaped, since it is coming from HTTP headers, i.e. potentially malicious source. In this case any occurrence of @@ would need escaping.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hmlnarik Good point regarding escaping. With regards to this, I don;t have any preference whether to use ":" or something like "@@" . Can be fine to stick with ":" if it's easier.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incidentally worked on another issue that also needs multi-field string serialization, and developed a tool for fast string (de)serialization, maybe it is worth reusing: https://github.com/keycloak/keycloak/pull/6139/files#diff-de17a5622aadad5857ba5697419c1e0b

@mposolda

mposolda commented Jul 1, 2019

Copy link
Copy Markdown
Contributor

Why there is a need to change the UserSessionModel? I believe the device info should be only placed there as a note, just the same as other notes, and used only when needed. This would limit the number of changes in the PR

+1 to this. The PR already delegates saving DeviceInfo to notes and doesn't introduce new property on infinispan UserSessionEntity, but if there is no need to change UserSessionModel and anything in infinispan models etc, it will be even better. How about having some utility like this?

    public static DeviceInfo getDeviceInfo(UserSessionModel userSession) {
        return DeviceInfo.create(userSession.getNotes().get(DeviceInfo.ID));
    }

    public static void setDeviceInfo(UserSessionModel userSession, DeviceInfo deviceInfo) {
        userSession.getNotes().put(DeviceInfo.ID, deviceInfo.toString());
    }

Or the approach similar to OIDCAdvancedConfigWrapper, which means allow to use nice java set/get methods for specified properties, but delegate to generic "attributes" at the model level, so there is no need to change models when new property is needed?

@mposolda

mposolda commented Jul 1, 2019

Copy link
Copy Markdown
Contributor

One more comment: I probably missed when/where it was decided that ua_parser is fine from various points of view (especially there are not any blockers from the productization perspective etc). I assume this was already agreed to go with ua_parser, but rather just asking.

@abstractj

Copy link
Copy Markdown
Contributor Author

Why there is a need to change the UserSessionModel? I believe the device info should be only placed there as a note, just the same as other notes, and used only when needed. This would limit the number of changes in the PR

+1 to this. The PR already delegates saving DeviceInfo to notes and doesn't introduce new property on infinispan UserSessionEntity, but if there is no need to change UserSessionModel and anything in infinispan models etc, it will be even better. How about having some utility like this?

    public static DeviceInfo getDeviceInfo(UserSessionModel userSession) {
        return DeviceInfo.create(userSession.getNotes().get(DeviceInfo.ID));
    }

    public static void setDeviceInfo(UserSessionModel userSession, DeviceInfo deviceInfo) {
        userSession.getNotes().put(DeviceInfo.ID, deviceInfo.toString());
    }

I was chatting with @douglaspalmer. Could you please help me with my ignorance about the codebase? Is model/infinispan/src/main/java/org/keycloak/models/sessions/infinispan/InfinispanUserSessionProvider the right place to add these methods?

Or the approach similar to OIDCAdvancedConfigWrapper, which means allow to use nice java set/get methods for specified properties, but delegate to generic "attributes" at the model level, so there is no need to change models when new property is needed?

@abstractj

Copy link
Copy Markdown
Contributor Author

Why there is a need to change the UserSessionModel? I believe the device info should be only placed there as a note, just the same as other notes, and used only when needed. This would limit the number of changes in the PR

@hmlnarik could you please point to the specific part of the code where we do what you mentioned here? I could not find exactly what you meant. Taking for example SamlService I see that we created methods inside AuthenticationSessionModel to set client notes. But it's better to confirm exactly what you mean here.

@abstractj
abstractj requested a review from pedroigor July 15, 2019 17:04

@hmlnarik hmlnarik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@abstractj Please see inline

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example here. If this is kept inside notes, there is no need to change this inner class.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For example here. If this is kept inside notes, there is no need to change this class.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E.g. here.

@pedroigor

Copy link
Copy Markdown
Contributor

@hmlnarik and @mposolda, after talking with @douglaspalmer about these changes we noticed that the changes herein are not really addressing the requirements we have in the new admin console.

Based on the wireframe (not the best source of requirements but what we have) we should store device activity independently of user sessions. In order to address the requirements, we need to actually store device activity, separately.

We also discussed the best approach to storing this data and we can go either by having a specific entity for device activity or just store it as a user attribute.

Although using user attributes provide a more simple implementation with only a few changes, I think creating a new entity is the best way to go.

@abstractj

Copy link
Copy Markdown
Contributor Author

@hmlnarik @mposolda thanks for taking the time reviewing it. I'm closing this PR for now because it's just a rebase from the @douglaspalmer changes. Like @pedroigor mentioned there are some requirements that we're not addressing in this change.

We are going to revisit it and open a new PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants