@ -37,6 +37,7 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe
private final PasswordHasher < String > passwordHasher ;
private final PasswordHasher < String > passwordHasher ;
private Map < String , AccessToken > accessTokens = new HashMap < > ( ) ;
private Map < String , AccessToken > accessTokens = new HashMap < > ( ) ;
private Map < String , Authorization > authCodes = new HashMap < > ( ) ;
private Map < String , Authorization > authCodes = new HashMap < > ( ) ;
private Map < String , String > nonceMap = new HashMap < > ( ) ;
private Authenticator auth ;
private Authenticator auth ;
public FileStore ( File storage , PasswordHasher < String > passwordHasher ) throws IOException {
public FileStore ( File storage , PasswordHasher < String > passwordHasher ) throws IOException {
@ -72,16 +73,15 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe
var clients = authorizations . getJSONObject ( userId ) ;
var clients = authorizations . getJSONObject ( userId ) ;
var clientIds = Set . copyOf ( clients . keySet ( ) ) ;
var clientIds = Set . copyOf ( clients . keySet ( ) ) ;
for ( var clientId : clientIds ) {
for ( var clientId : clientIds ) {
var clientData = clients . getJSONObject ( clientId ) ;
var client = clients . getJSONObject ( clientId ) ;
var scopeMap = clientData . getJSONObject ( SCOPE ) ;
var scopes = Set . copyOf ( client . keySet ( ) ) ;
var scopes = Set . copyOf ( scopeMap . keySet ( ) ) ;
for ( var scope : scopes ) {
for ( var scope : scopes ) {
var expiration = Instant . ofEpochSecond ( scopeMap . getLong ( scope ) ) ;
var expiration = Instant . ofEpochSecond ( client . getLong ( scope ) ) ;
if ( expiration . isBefore ( now ) ) {
if ( expiration . isBefore ( now ) ) {
scopeMap . remove ( scope ) ;
client . remove ( scope ) ;
}
}
}
}
if ( scopeMap . isEmpty ( ) ) clients . remove ( clientId ) ;
if ( client . isEmpty ( ) ) clients . remove ( clientId ) ;
}
}
if ( clients . isEmpty ( ) ) authorizations . remove ( userId ) ;
if ( clients . isEmpty ( ) ) authorizations . remove ( userId ) ;
}
}
@ -298,7 +298,7 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe
@Override
@Override
public ClientService save ( Client client ) {
public ClientService save ( Client client ) {
if ( ! json . has ( CLIENTS ) ) json . put ( CLIENTS , new JSONObject ( ) ) ;
if ( ! json . has ( CLIENTS ) ) json . put ( CLIENTS , new JSONObject ( ) ) ;
json . getJSONObject ( CLIENTS ) . put ( client . id ( ) , client . map ( ) ) ;
json . getJSONObject ( CLIENTS ) . put ( client . id ( ) , Map . of ( NAME , client . na me ( ) , SECRET , client . secret ( ) , REDIRECT_URIS , client . redirectUris ( ) ) ) ;
save ( ) ;
save ( ) ;
return this ;
return this ;
}
}
@ -311,7 +311,7 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe
return new Client ( clientId , clientData . getString ( NAME ) , clientData . getString ( SECRET ) , redirectUris ) ;
return new Client ( clientId , clientData . getString ( NAME ) , clientData . getString ( SECRET ) , redirectUris ) ;
}
}
/*** Claim AuthorizationService methods ***/
/*** AuthorizationService methods ***/
private String authCode ( Authorization authorization ) {
private String authCode ( Authorization authorization ) {
var code = uuid ( ) ;
var code = uuid ( ) ;
authCodes . put ( code , authorization ) ;
authCodes . put ( code , authorization ) ;
@ -319,20 +319,13 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe
}
}
@Override
@Override
public AuthorizationService authorize ( String userId , String clientId , Collection < String > scopes , String nonce , Instant expiration ) {
public AuthorizationService authorize ( String userId , String clientId , Collection < String > scopes , Instant expiration ) {
if ( ! json . has ( AUTHORIZATIONS ) ) json . put ( AUTHORIZATIONS , new JSONObject ( ) ) ;
if ( ! json . has ( AUTHORIZATIONS ) ) json . put ( AUTHORIZATIONS , new JSONObject ( ) ) ;
var authorizations = json . getJSONObject ( AUTHORIZATIONS ) ;
var authorizations = json . getJSONObject ( AUTHORIZATIONS ) ;
if ( ! authorizations . has ( userId ) ) authorizations . put ( userId , new JSONObject ( ) ) ;
if ( ! authorizations . has ( userId ) ) authorizations . put ( userId , new JSONObject ( ) ) ;
var userAuthorizations = authorizations . getJSONObject ( userId ) ;
var userAuthorizations = authorizations . getJSONObject ( userId ) ;
if ( ! userAuthorizations . has ( clientId ) ) userAuthorizations . put ( clientId , new JSONObject ( ) ) ;
if ( ! userAuthorizations . has ( clientId ) ) userAuthorizations . put ( clientId , new JSONObject ( ) ) ;
var clientData = userAuthorizations . getJSONObject ( clientId ) ;
var clientScopes = userAuthorizations . getJSONObject ( clientId ) ;
if ( nonce ! = null ) {
clientData . put ( NONCE , nonce ) ;
} else {
if ( clientData . has ( NONCE ) ) clientData . remove ( NONCE ) ;
}
if ( ! clientData . has ( SCOPE ) ) clientData . put ( SCOPE , new JSONObject ( ) ) ;
var clientScopes = clientData . getJSONObject ( SCOPE ) ;
for ( var scope : scopes ) clientScopes . put ( scope , expiration . getEpochSecond ( ) ) ;
for ( var scope : scopes ) clientScopes . put ( scope , expiration . getEpochSecond ( ) ) ;
save ( ) ;
save ( ) ;
return this ;
return this ;
@ -344,15 +337,19 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe
return nullable ( authCodes . remove ( authCode ) ) ;
return nullable ( authCodes . remove ( authCode ) ) ;
}
}
@Override
public Optional < String > consumeNonce ( String userId , String clientId ) {
var nonceKey = String . join ( "@" , userId , clientId ) ;
return nullable ( nonceMap . get ( nonceKey ) ) ;
}
@Override
@Override
public AuthResult getAuthorization ( String userId , String clientId , Collection < String > scopes ) {
public AuthResult getAuthorization ( String userId , String clientId , Collection < String > scopes ) {
if ( ! json . has ( AUTHORIZATIONS ) ) return unauthorized ( scopes ) ;
if ( ! json . has ( AUTHORIZATIONS ) ) return unauthorized ( scopes ) ;
var authorizations = json . getJSONObject ( AUTHORIZATIONS ) ;
var authorizations = json . getJSONObject ( AUTHORIZATIONS ) ;
var userAuthorizations = authorizations . has ( userId ) ? authorizations . getJSONObject ( userId ) : null ;
var userAuthorizations = authorizations . has ( userId ) ? authorizations . getJSONObject ( userId ) : null ;
if ( userAuthorizations = = null ) return unauthorized ( scopes ) ;
if ( userAuthorizations = = null ) return unauthorized ( scopes ) ;
var clientData = userAuthorizations . has ( clientId ) ? userAuthorizations . getJSONObject ( clientId ) : null ;
var clientScopes = userAuthorizations . has ( clientId ) ? userAuthorizations . getJSONObject ( clientId ) : null ;
if ( clientData = = null ) return unauthorized ( scopes ) ;
var clientScopes = clientData . has ( SCOPE ) ? clientData . getJSONObject ( SCOPE ) : null ;
if ( clientScopes = = null ) return unauthorized ( scopes ) ;
if ( clientScopes = = null ) return unauthorized ( scopes ) ;
var now = Instant . now ( ) ;
var now = Instant . now ( ) ;
var authorizedScopes = new HashSet < String > ( ) ;
var authorizedScopes = new HashSet < String > ( ) ;
@ -371,11 +368,19 @@ public class FileStore implements AuthorizationService, ClientService, SessionSe
}
}
if ( authorizedScopes . isEmpty ( ) ) return unauthorized ( scopes ) ;
if ( authorizedScopes . isEmpty ( ) ) return unauthorized ( scopes ) ;
String nonce = clientData . has ( NONCE ) ? clientData . getString ( NONCE ) : null ;
var authorization = new Authorization ( clientId , userId , new AuthorizedScopes ( authorizedScopes , earliestExpiration ) ) ;
var authorization = new Authorization ( clientId , userId , new AuthorizedScopes ( authorizedScopes , earliestExpiration ) , nonce ) ;
return new AuthResult ( authorization . scopes ( ) , unauthorizedScopes , authCode ( authorization ) ) ;
return new AuthResult ( authorization . scopes ( ) , unauthorizedScopes , authCode ( authorization ) ) ;
}
}
@Override
public void nonce ( String userId , String clientId , String nonce ) {
var nonceKey = String . join ( "@" , userId , clientId ) ;
if ( nonce ! = null ) {
nonceMap . put ( nonceKey , nonce ) ;
} else
nonceMap . remove ( nonceKey ) ;
}
private AuthResult unauthorized ( Collection < String > scopes ) {
private AuthResult unauthorized ( Collection < String > scopes ) {
return new AuthResult ( null , new HashSet < > ( scopes ) , null ) ;
return new AuthResult ( null , new HashSet < > ( scopes ) , null ) ;
}
}