Hi all,
I'm hoping someone can help me with this. I've been working on it for a few weeks and can't figure it out. Thank you in advance for any assistance you may be willing/able to offer.
OK, here's the situation:
I've got a 2 panel dashboard: statistics table on left and cluster map on right. The table side seems to be working great. The map is populating, but when I click on a dot to open a new tab and get more details I keep running into a "phantom IP'-type of issue.
Dashboard XML:
<form version="1.1" theme="light">
<label>Impossible Travel (ALL USERS)</label>
<fieldset submitButton="true" autoRun="true">
<input type="time" token="time_tok" searchWhenChanged="false">
<label>Time Range</label>
<default>
<earliest>-96h@h</earliest>
<latest>now</latest>
</default>
</input>
<input type="text" token="user_search_tok" searchWhenChanged="false">
<label>Search User (Email or First Last)</label>
<default>*</default>
</input>
</fieldset>
<row>
<panel>
<table>
<search>
<query>index=okta outcome.result IN ("SUCCESS", "ALLOW")
NOT (client.ipAddress="34.192.0.0/12" OR client.ipAddress="34.194.*")
NOT (*Guest* OR *Bontemps* OR "Okta System*" OR "Okta Dashboard*" OR "Okta Browser Plugin" OR "Pharos Beacon" OR "EchoVideo" OR "Omnigo Identity Server" OR "Drata" OR "Okta Administration" OR "Active Directory Agent")
| iplocation client.ipAddress
| eval City = if(cidrmatch("149.150.0.0/16", client.ipAddress), "SHU Campus", City)
| sort 0 actor.alternateId _time
| streamstats window=2 current=f last(lat) as prev_lat last(lon) as prev_lon last(City) as prev_city last(Country) as prev_country last(Region) as prev_state last(_time) as prev_time by actor.alternateId
| where isnotnull(prev_city) AND City != prev_city
| eval duration = _time - prev_time
| eval h = floor(duration/3600)
| eval m = floor((duration%3600)/60)
| eval Time_Between = case(h > 0, h."hr ".m."min", m > 0, m."min", 1=1, "0min")
| where duration <= 7200
| eval user_name = coalesce('actor.displayName', display_name, "Unknown")
| eval lat1 = lat*pi()/180, lon1 = lon*pi()/180, lat2 = prev_lat*pi()/180, lon2 = prev_lon*pi()/180
| eval dlat = lat2 - lat1, dlon = lon2 - lon1
| eval a = pow(sin(dlat/2),2) + cos(lat1) * cos(lat2) * pow(sin(dlon/2),2)
| eval c = 2 * atan2(sqrt(a), sqrt(1-a))
| eval distance_miles = round(3958.8 * c, 2)
| eval City = mvappend(prev_city, City)
| eval State = if(prev_state == Region, Region, mvappend(prev_state, Region))
| eval Country = if(prev_country == Country, Country, mvappend(prev_country, Country))
| fieldformat _time = strftime(_time, "%d %b %Y %l:%M%p")
| sort - _time
| table _time, user_name, actor.alternateId, City, State, Country, distance_miles, Time_Between
| rename user_name as "User", actor.alternateId as "Email", distance_miles as "Mileage", Time_Between as "Time Between Entries"</query>
<earliest>$time_tok.earliest$</earliest>
<latest>$time_tok.latest$</latest>
</search>
<option name="drilldown">none</option>
<option name="refresh.display">progressbar</option>
<format type="color" field="Country">
<colorPalette type="expression">if(value != "United States" AND isnotnull(value) AND value != "" AND value != "Internal/NJ" AND value != "SHU Campus", "#27F2F5", "")</colorPalette>
</format>
<format type="color" field="Mileage">
<colorPalette type="expression">case(value > 1000, "#FFFF00")</colorPalette>
</format>
</table>
</panel>
<panel>
<title>Impossible Travel Map</title>
<map>
<search>
<query>index=okta outcome.result IN ("SUCCESS", "ALLOW")
NOT (client.ipAddress="34.192.0.0/12" OR client.ipAddress="34.194.*")
NOT (*Guest* OR *Bontemps* OR "Okta System*" OR "Okta Dashboard*" OR "Okta Browser Plugin" OR "Pharos Beacon" OR "EchoVideo")
| iplocation client.ipAddress
| eval City = if(cidrmatch("149.150.0.0/16", client.ipAddress), "SHU Campus", City)
| sort 0 actor.alternateId _time
| streamstats window=2 current=f last(City) as prev_city last(_time) as prev_time by actor.alternateId
| where isnotnull(prev_city) AND City != prev_city
| eval duration = _time - prev_time
| where duration <= 7200
| geostats latfield=lat longfield=lon globallimit=0 maxzoomlevel=18 count by client.ipAddress</query>
<earliest>$time_tok.earliest$</earliest>
<latest>$time_tok.latest$</latest>
</search>
<option name="height">600</option>
<option name="mapping.seriesColors">[0x00FF00, 0xFFFF00, 0xFF00FF, 0x00FFFF, 0xFFFFFF, 0xFF9900]</option>
<option name="mapping.type">marker</option>
<option name="refresh.display">progressbar</option>
<drilldown>
<link target="_blank">
<![CDATA[/app/search/search?q=search index=okta | iplocation client.ipAddress | where (lat > ($click.lat$ - 0.1) AND lat < ($click.lat$ + 0.1)) AND (lon > ($click.lon$ - 0.1) AND lon < ($click.lon$ + 0.1)) | eval City = if(cidrmatch("149.150.0.0/16", client.ipAddress), "SHU Campus", City) | table _time, actor.alternateId, City, client.ipAddress, outcome.result&earliest=$time_tok.earliest$&latest=$time_tok.latest$]]>
</link>
</drilldown>
</map>
</panel>
</row>
</form>
Dot click SPL returned in new tab:
The SPL returned varies a bit. The overall general format is
index=okta | iplocation client.ipAddress | search City="*104.28.56.1*" OR client.ipAddress="*104.28.56.1*" | eval City = if(cidrmatch("149.150.0.0/16", client.ipAddress), "SHU Campus", City) | table _time, actor.alternateId, City, client.ipAddress, outcome.result
However, the IP address in City="IP" OR client.ipAddress = "IP" varies depending on the search timeframe. I get different IPs returned for 4, 8, 12 and 24 hour searches.
What I'm trying to get to is when I click the dot a new tab opens and I see details about the user, IP address and location coming from and (if possible) IP address and location going to in that dot region.
I feel like everything is good except for the dot click details that get returned.