In Non Reactive Spring Security we Have Plugin Point For custom Security Context Impl By Following snippet in SecurityContextHolder with following snippet:
private static void initialize() { if (!StringUtils.hasText(strategyName)) { strategyName = "MODE_THREADLOCAL"; }
if (strategyName.equals("MODE_THREADLOCAL")) {
strategy = new ThreadLocalSecurityContextHolderStrategy();
} else if (strategyName.equals("MODE_INHERITABLETHREADLOCAL")) {
strategy = new InheritableThreadLocalSecurityContextHolderStrategy();
} else if (strategyName.equals("MODE_GLOBAL")) {
strategy = new GlobalSecurityContextHolderStrategy();
} else {
try {
Class<?> clazz = Class.forName(strategyName);
Constructor<?> customStrategy = clazz.getConstructor();
strategy = (SecurityContextHolderStrategy)customStrategy.newInstance();
} catch (Exception var2) {
ReflectionUtils.handleReflectionException(var2);
}
}
++initializeCount;
}
and using custom SecurityContextHolderStrategy.
But reactive support does not have any such mechanism. It directly creates SecurityContextImp as instance of SecurityContex. We can change it by overiding onAuthenticationSuccess method. But it will be a mess if we are using many authentication method together like Basic, Form and OAuth, then we will have to change AuthenticationFilter for each type. And it will also not allow to take advantages of many defaults convention as we will have to do lot of configuration. So we should have plugin point for custom SecurityContext implementation. We may add ReactiveSecurityContextHolderStrategy or something similar.
```protected Mono
**Comment From: rwinch**
Thanks for the report @ankurpathak!
I don't see this feature being used much in the servlet world and have my doubts that we should add it for reactive Spring Security. Can you elaborate on your usecase?
**Comment From: ankurpathak**
Well their are number of use case:
1. Lets take example of mobile number based login. In India mobile number are like +91XXXXXXXXXX.
When I login by mobile number I can login by entering +91XXXXXXXXXX. But entering that country dial
code +91 with my mobile number for logging every time is a mess. So we can translate IP of Person
to Country and append all possible dial code of that country to form possible candidate keys. And write Or query with all possible candidate keys to login. In UserDetailsService we don't have access to User Ip
so, before goint to UserDetailsService I would like to save my IP in DomainContext on custom SecurityContext and do all the above process in UserDetailsService.
@Override
public Mono
public static final String KEY_EMAIL = "email.value";
public static final String KEY_CONTACT = "contact.value";
public static final String KEY_USERNAME = "username";
public static final String KEY_ID = "_id";
public static final Map<String, String> KEY_MAPPINGS = new LinkedHashMap<>();
static {
KEY_MAPPINGS.put(Params.ID, KEY_ID);
KEY_MAPPINGS.put(Params.USERNAME, KEY_USERNAME);
KEY_MAPPINGS.put(Params.EMAIL, KEY_EMAIL);
KEY_MAPPINGS.put(Params.CONTACT, KEY_CONTACT);
}
@Override
public Flux
if (StringValidator.email(username, false))
possibleKeys.put(Params.EMAIL, username);
else if (StringValidator.contact(username, false))
possibleKeys.put(Params.CONTACT, username);
BigInteger possibleId = PrimitiveUtils.toBigInteger(username);
if (possibleId.compareTo(BigInteger.ZERO) > 0) {
possibleKeys.put(Params.ID, possibleId);
}
possibleKeys.put(Params.USERNAME, username);
return Flux.fromIterable(possibleKeys.entrySet());
}
@Override
public Flux<String> possibleContacts(String username) {
require(username, not(emptyString()));
if (!StringUtils.isNumeric(username))
return Flux.empty();
return// SecurityUtil.getDomainContext()
// .flatMap(DomainContext::getRemoteAddress)
Mono.just("155.94.180.97")
.flatMap(ipService::ipToCountryAlphaCode)
.flatMapMany(countryService::alphaCodeToCallingCodes)
.map(callingCode -> String.format("+%s%s", callingCode, username));
}
**Comment From: ankurpathak**
2. Lets take the example of application which uses User specific and Organization specific collections like:
@Document(collection = Product.COLLECTION)
public class Product extends ExtendedDomain
Comment From: ankurpathak
- Lets take the use case of 2FA Authentication with Google Authenticator. In this case we can store that Google Authenticator Code send with username and password on DomainContext on Custom SecurityContext.
Comment From: ankurpathak
- In General any extra application specific information used in Authntication, authorization can be stored in DomainContext in custom SecurityContext. I see this as the best place of storeing it as stated by @jgrandja in his talk Spring Security deep dive: https://www.youtube.com/watch?v=AdsnM6OTepc.
Comment From: rwinch
This really seems like a duplicate of #6137 so let's move the discussion there
Comment From: ankurpathak
@rwinch Sure.Should I move all points listed here to that discussion.