-
Notifications
You must be signed in to change notification settings - Fork 640
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
jwt blacklist stop play/publish using jwt #4847
base: master
Are you sure you want to change the base?
Conversation
final JSONParser parser = new JSONParser(); | ||
try { | ||
final JSONObject jwtPayload = (JSONObject) parser.parse(payload); | ||
final String tokenType = jwtPayload.get("type").toString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NULLPTR_DEREFERENCE: null (last assigned on line 1283) is dereferenced.
ℹ️ Expand to see all @sonatype-lift commands
You can reply with the following commands. For example, reply with @sonatype-lift ignoreall to leave out all findings.
Command | Usage |
---|---|
@sonatype-lift ignore |
Leave out the above finding from this PR |
@sonatype-lift ignoreall |
Leave out all the existing findings from this PR |
@sonatype-lift exclude <file|issue|path|tool> |
Exclude specified file|issue|path|tool from Lift findings by updating your config.toml file |
Note: When talking to LiftBot, you need to refresh the page to see its response.
Click here to add LiftBot to another repo.
Help us improve LIFT! (Sonatype LiftBot external survey)
Was this a good recommendation for you? Answering this survey will not impact your Lift settings.
[ 🙁 Not relevant ] - [ 😕 Won't fix ] - [ 😑 Not critical, will fix ] - [ 🙂 Critical, will fix ] - [ 😊 Critical, fixing now ]
logger.info("Deleting all expired JWTs from black list."); | ||
|
||
AtomicInteger deletedTokenCount = new AtomicInteger(); | ||
tokenBlacklistMap.forEach((key, value) -> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
THREAD_SAFETY_VIOLATION: Read/Write race. Non-private method MapBasedDataStore.deleteAllExpiredJwtFromBlacklist(...)
reads without synchronization from container this.tokenBlacklistMap
via call to Map.forEach(...)
. Potentially races with write in method MapBasedDataStore.deleteTokenFromBlacklist(...)
.
Reporting because another access to the same memory occurs on a background thread, although this access may not.
ℹ️ Expand to see all @sonatype-lift commands
You can reply with the following commands. For example, reply with @sonatype-lift ignoreall to leave out all findings.
Command | Usage |
---|---|
@sonatype-lift ignore |
Leave out the above finding from this PR |
@sonatype-lift ignoreall |
Leave out all the existing findings from this PR |
@sonatype-lift exclude <file|issue|path|tool> |
Exclude specified file|issue|path|tool from Lift findings by updating your config.toml file |
Note: When talking to LiftBot, you need to refresh the page to see its response.
Click here to add LiftBot to another repo.
Help us improve LIFT! (Sonatype LiftBot external survey)
Was this a good recommendation for you? Answering this survey will not impact your Lift settings.
[ 🙁 Not relevant ] - [ 😕 Won't fix ] - [ 😑 Not critical, will fix ] - [ 🙂 Critical, will fix ] - [ 😊 Critical, fixing now ]
🛠 Lift Auto-fixSome of the Lift findings in this PR can be automatically fixed. You can download and apply these changes in your local project directory of your branch to review the suggestions before committing.1 # Download the patch
curl https://lift.sonatype.com/api/patch/github.com/ant-media/Ant-Media-Server/4847.diff -o lift-autofixes.diff
# Apply the patch with git
git apply lift-autofixes.diff
# Review the changes
git diff Want it all in a single command? Open a terminal in your project's directory and copy and paste the following command: curl https://lift.sonatype.com/api/patch/github.com/ant-media/Ant-Media-Server/4847.diff | git apply Once you're satisfied, commit and push your changes in your project. Footnotes |
d36062e
to
9542943
Compare
f7d1669
to
94b6fd0
Compare
94b6fd0
to
fc28eed
Compare
@Produces(MediaType.APPLICATION_JSON) | ||
public List<String> getJwtBlacklist() | ||
{ | ||
if(getAppSettings().isJwtBlacklistEnabled()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NULL_DEREFERENCE: object returned by getAppSettings()
could be null and is dereferenced at line 687.
ℹ️ Expand to see all @sonatype-lift commands
You can reply with the following commands. For example, reply with @sonatype-lift ignoreall to leave out all findings.
Command | Usage |
---|---|
@sonatype-lift ignore |
Leave out the above finding from this PR |
@sonatype-lift ignoreall |
Leave out all the existing findings from this PR |
@sonatype-lift exclude <file|issue|path|tool> |
Exclude specified file|issue|path|tool from Lift findings by updating your config.toml file |
Note: When talking to LiftBot, you need to refresh the page to see its response.
Click here to add LiftBot to another repo.
Help us improve LIFT! (Sonatype LiftBot external survey)
Was this a good recommendation for you? Answering this survey will not impact your Lift settings.
[ 🙁 Not relevant ] - [ 😕 Won't fix ] - [ 😑 Not critical, will fix ] - [ 🙂 Critical, will fix ] - [ 😊 Critical, fixing now ]
19945a7
to
0bd2319
Compare
jwt. blacklist using already existed token db with flag
0bd2319
to
7543ea1
Compare
public Result blackListOrWhitelistJwt(@ApiParam(value = "jwt to be added to blacklist.", required = true) @QueryParam("jwt") String jwt, | ||
@ApiParam(value = "if true whitelist jwt (unblacklist)", required = false) @QueryParam("whiteList") boolean whiteList) | ||
{ | ||
if(getAppSettings().isJwtBlacklistEnabled()){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NULL_DEREFERENCE: object returned by getAppSettings()
could be null and is dereferenced at line 618.
ℹ️ Expand to see all @sonatype-lift commands
You can reply with the following commands. For example, reply with @sonatype-lift ignoreall to leave out all findings.
Command | Usage |
---|---|
@sonatype-lift ignore |
Leave out the above finding from this PR |
@sonatype-lift ignoreall |
Leave out all the existing findings from this PR |
@sonatype-lift exclude <file|issue|path|tool> |
Exclude specified file|issue|path|tool from Lift findings by updating your config.toml file |
Note: When talking to LiftBot, you need to refresh the page to see its response.
Click here to add LiftBot to another repo.
Help us improve LIFT! (Sonatype LiftBot external survey)
Was this a good recommendation for you? Answering this survey will not impact your Lift settings.
[ 🙁 Not relevant ] - [ 😕 Won't fix ] - [ 😑 Not critical, will fix ] - [ 🙂 Critical, will fix ] - [ 😊 Critical, fixing now ]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unrelated but i didnt like the naming of this blackListOrWhitelistJwt function but couldnt find something better. Previously there were 2 different api calls one for blacklisting other for whitelisting but i changed to this. im sure someone can come up with a better naming.
SonarCloud Quality Gate failed. |
@Path("/jwt-black-list") | ||
@Produces(MediaType.APPLICATION_JSON) | ||
public Result blackListOrWhitelistJwt(@ApiParam(value = "jwt to be added to blacklist.", required = true) @QueryParam("jwt") String jwt, | ||
@ApiParam(value = "if true whitelist jwt (unblacklist)", required = false) @QueryParam("whiteList") boolean whiteList) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sending a POST to /jwt-black-list?whiteList=true
seems a bit weird to me, just read back the docs: "unblacklist".. Would it not be clearer if one had to send a DELETE request to the collection /jwt-black-list
to get something removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is not removing anything from disk thats why i made it a post call.
But we can also make it a delete
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not the disk that matters, but it does remove someone from the blacklist, so I think a DELETE would be a better choice.
* | ||
* @return | ||
*/ | ||
public abstract boolean whiteListAllTokens(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The concept of allowing only people with valid tokens is implicitly a whitelist, so I think you should not give the impression that there is a separate whitelist and a blacklist. Is it not only clearing the blacklist..?
@Override | ||
public boolean whiteListAllTokens(){ | ||
|
||
synchronized (this) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using this
as a synchronization point might not be a good choice as other classes can still hold a lock on this class. I would suggest using a non-public internal locking mechanism for synchronization purposes, which is more fine-grained and only applies to operations on the tokenMap, e.g. a ReadWriteLock
or similar.
public boolean blackListToken(Token token) { | ||
boolean result = false; | ||
|
||
synchronized (this) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd revisit the usage of synchronized
in this class, as there seems to be some overuse and overscoping. Using this
as a monitor is not very fortunate, as it can be held externally. Here the monitor is obtained too early, only saveToken
seems to be critical, but as far as I can see saveToken
itself also takes care of synchronization using this
, so this might be completely unnecessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agree
public boolean blackListToken(Token token) { | ||
boolean result = false; | ||
//update if exists, else insert | ||
synchronized (this) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The scope of the synchronized block looks unnecessarily broad and blocks other concurrent operations in the store. Sorry if I misunderstand, but if you are trying to ensure some kind of atomic transaction here so that the find-update-save
cannot be interrupted, then what about other JVM participants in the cluster, that are not held up by the lock, hence can still concurrently fiddle with Mongo?
synchronized (this){ | ||
Query<Token> query = tokenDatastore.find(Token.class).filter(Filters.eq(BLACKLISTED, true)); | ||
for (Token token : query) { | ||
tokenBlacklist.add(token.getTokenId()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it necessary to hold the monitor as long as the iteration processes all the tokens?
I would suggest not using query parameters for mandatory data required for a POST to happen. Concretely I would not recommend sending the blacklisted JWT via query parameter, but POST body. Query parameters could be used for optional things instead (remember the ? mark), that narrow down or refine the results of a GET request. |
@Produces(MediaType.APPLICATION_JSON) | ||
public Result blackListJwt(@ApiParam(value = "jwt to be added to blacklist.", required = true) @RequestBody Jwt jwt) | ||
{ | ||
if(getAppSettings().isJwtBlacklistEnabled()){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NULL_DEREFERENCE: object returned by getAppSettings()
could be null and is dereferenced at line 618.
ℹ️ Expand to see all @sonatype-lift commands
You can reply with the following commands. For example, reply with @sonatype-lift ignoreall to leave out all findings.
Command | Usage |
---|---|
@sonatype-lift ignore |
Leave out the above finding from this PR |
@sonatype-lift ignoreall |
Leave out all the existing findings from this PR |
@sonatype-lift exclude <file|issue|path|tool> |
Exclude specified file|issue|path|tool from Lift findings by updating your config.toml file |
Note: When talking to LiftBot, you need to refresh the page to see its response.
Click here to add LiftBot to another repo.
@Produces(MediaType.APPLICATION_JSON) | ||
public Result whiteListJwt(@ApiParam(value = "Jwt to be removed from blacklist.", required = true) @QueryParam("jwt") String jwt) | ||
{ | ||
if(getAppSettings().isJwtBlacklistEnabled()){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NULL_DEREFERENCE: object returned by getAppSettings()
could be null and is dereferenced at line 667.
ℹ️ Expand to see all @sonatype-lift commands
You can reply with the following commands. For example, reply with @sonatype-lift ignoreall to leave out all findings.
Command | Usage |
---|---|
@sonatype-lift ignore |
Leave out the above finding from this PR |
@sonatype-lift ignoreall |
Leave out all the existing findings from this PR |
@sonatype-lift exclude <file|issue|path|tool> |
Exclude specified file|issue|path|tool from Lift findings by updating your config.toml file |
Note: When talking to LiftBot, you need to refresh the page to see its response.
Click here to add LiftBot to another repo.
a16a4c1
to
06b4627
Compare
@Produces(MediaType.APPLICATION_JSON) | ||
public Result whiteListJwt(@ApiParam(value = "Jwt to be removed from blacklist.", required = true) Jwt jwt) | ||
{ | ||
if(getAppSettings().isJwtBlacklistEnabled()){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NULL_DEREFERENCE: object returned by getAppSettings()
could be null and is dereferenced at line 667.
ℹ️ Expand to see all @sonatype-lift commands
You can reply with the following commands. For example, reply with @sonatype-lift ignoreall to leave out all findings.
Command | Usage |
---|---|
@sonatype-lift ignore |
Leave out the above finding from this PR |
@sonatype-lift ignoreall |
Leave out all the existing findings from this PR |
@sonatype-lift exclude <file|issue|path|tool> |
Exclude specified file|issue|path|tool from Lift findings by updating your config.toml file |
Note: When talking to LiftBot, you need to refresh the page to see its response.
Click here to add LiftBot to another repo.
SonarCloud Quality Gate failed. 0 Bugs 66.0% Coverage Catch issues before they fail your Quality Gate with our IDE extension SonarLint |
7eb7818
to
2fc0ea8
Compare
#4809
This pull request introduces a JWT blacklist implementation, which allows users to ban viewers who are already watching or publishing streams. Since JWTs are not meant to be stored in a database, this feature is not enabled by default. However, a new setting called "jwtBlacklistEnabled" has been added to app settings. Otherwise, each request with a JWT would trigger a database lookup on disk, leading to degraded performance. This feature has several use cases, such as stopping HLS/DASH and WebRTC viewers who are already watching, and stoping WebRTC publishers from publishing who are already publishing. Mostly useful for AMS users who are mapping their viewers using JWT tokens by including some userId in token.
There is no new data storage created to avoid token duplication since tokens are already stored in database on disk. Adding a token to blacklist means setting its blackListed flag to true. If token doesnt exist it inserts. Whitelisting a token means setting its blackListed flag to false.
For example, AMS users who wants to prevent a viewer who is already watching a stream with HLS/DASH can enable the JWT blacklist feature and add the user's JWT token to the blacklist(set its blacklisted flag to true, if not exists insert with blacklisted flag true) using a new API call. When the viewer requests the next video chunk, the server won't return it because the token is blacklisted. To allow the viewer to watch again, the user can whitelist the token by using same API call with whiteFlag parameter true.
Example blacklist http call:
curl --location --request POST 'http://localhost:5080/WebRTCAppEE/rest/v2/broadcasts/jwt-black-list?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdHJlYW1JZCI6InRlc3RzdHJlYW0iLCJ0eXBlIjoicGxheSIsImV4cCI6Mjg4NzUwOTMwMX0.pZ2X8HxqXiUn_pSheky_J61z2HEs-cgjG8ikB4MZ1AE' \
Example whitelist http call:
curl --location --request POST 'http://localhost:5080/WebRTCAppEE/rest/v2/broadcasts/jwt-black-list?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdHJlYW1JZCI6InRlc3RzdHJlYW0iLCJ0eXBlIjoicGxheSIsImV4cCI6Mjg4NzUwOTMwMX0.pZ2X8HxqXiUn_pSheky_J61z2HEs-cgjG8ikB4MZ1AE&whiteList=true' \
Similarly, if an AMS user wants to prevent a WebRTC viewer from watching a stream, they can stop the viewer using the "/webrtc-viewers/stop" API route with users JWT. This call will disconnect webrtc viewer. Then AMS user can add JWT to blacklist so when page is refreshed stream wont play.
https://github.com/ant-media/Ant-Media-Server/pull/4738/files#diff-c0d849875e95960ae6cb3780196fe1dcb6d87a19f9e5f2784627c074752edac0
JWT's in AMS needs to contain streamId. AMS user can use stopStreamingV2 api call to stop given stream by extracting stream Id from users JWT. After stoping publish, user's JWT can be added to the blacklist, preventing them from publishing again until the token is whitelisted with api call.
There are also two other utility api calls /jwt-black-list-delete-expired and /jwt-black-list-clear
/jwt-black-list-delete-expired deletes all expired(invalid) and blacklisted tokens from database.
/jwt-black-list-clear white lists all jwts.
jwt-black-list-delete-expired can be valuable if used periodically to prevent the tokenlist from growing infinitely when too many items are added.
Overall, this pull request enhances the functionality of AMS by adding a JWT blacklist feature that gives users greater control over who can watch and publish streams. Mostly useful to stop playing and publishing users who are already doing it.
API calls can be refactored to different names and style if found complicated.