WSO2is: Get an exception custom message using SCIM command - wso2

I'm writing a simple custom user store manager for wso2is.
this is the code:
public class CustomJDBCUserStoreManager extends JDBCUserStoreManager {
private static Log log = LogFactory.getLog(CustomJDBCUserStoreManager.class);
public CustomJDBCUserStoreManager() {
}
public CustomJDBCUserStoreManager(org.wso2.carbon.user.api.RealmConfiguration realmConfig,
Map<String, Object> properties,
ClaimManager claimManager,
ProfileConfigurationManager profileManager,
UserRealm realm, Integer tenantId)
throws UserStoreException {
super(realmConfig, properties, claimManager, profileManager, realm, tenantId, false);
}
#Override
public void doAddUser(String userName, Object credential, String[] roleList,
Map<String, String> claims, String profileName,
boolean requirePasswordChange) throws UserStoreException {
String[] users = super.doListUsers( "*", -1);
int nUser = users.length;
if (nUser > 5){
throw new UserStoreException( "Reached the maximum number of global users" );
}else{
super.doAddUser( userName, credential, roleList, claims, profileName, requirePasswordChange );
}
}
}
The code work. When i try to insert from interface a number of user > 5, the interface give me the Exception message "Reached the maximum number of global users".
But when I try to add a user by SCIM over the 5 user I have the message:
{"Errors":[{"description":"Error in adding the user: mrossi to the user store..","code":"500"}]}
Well, in this point I need to get the correct message exception "Reached the maximum number of global users" and not a generic message "Error in adding the user".
Is there a way to do it?
thanks.

If you have problems with building particular component. You can try it [a] Identity Server next release.
build it with maven and you can find distribution inside "product-is/modules/distribution/target".
[a] https://github.com/wso2/product-is/

You need to do little code modification to SCIM provider component.
What is the version of WSO2 Identity Server you are using so that I can point you

Please refer below link [1]. In SCIMUserManager class line 159 change "Error in adding the user: " + user.getUserName() + " to the user store.." to e.getMessage() and replace wso2.war in repository/deployment/server/webapps also delete wso2 directory
[1] https://svn.wso2.org/repos/wso2/carbon/platform/branches/turing/components/identity/org.wso2.carbon.identity.scim.provider/4.2.2/src/main/java/org/wso2/carbon/identity/scim/provider/impl

Related

WSO2 Identity Server 5.7.0 - Password Policy Request for Minimum Password Age

I have researched at length all of the password policy options that have been added to the latest WSO2 Identity Server (5.7.0). While a big improvement over versions just a year old, my customer still is not satisfied over one issue. Using a password policy authenticator, looks like we can force a user to change their password every so many days, and using the now default policy options can enforce a password history requirement of any number to our liking. However, the history option could be overcome by a determined user simply changing his password the number of times required to age his password quickly in a single setting--unless there were a required "minimum password age" that would preclude them from doing so. All available options in History, Patterns, and Password Authenticator do not address this. This reference from Windows 10 security threat protection addresses the validity of this very issue: https://learn.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/minimum-password-age.
Is there a way I can set a minimum age in WSO2 IS now also? If not, should this not be included as a password policy in the history options?
This feature is not currently available in the WSO2 IS product, But we can fulfil this requirement easily using the extensions available in the core user management system.
The available password history feature has the history of the changed password dateTime, we can use those data to enforce this requirement.
Create a new Identity Connector to configure the minimum password age and Abstract Event Handler to enforce the validation during password change event.
public class PasswordMinAgeValidationHandler extends AbstractEventHandler implements IdentityConnectorConfig {
private static final Log log = LogFactory.getLog(PasswordMinAgeValidationHandler.class);
#Override
public void handleEvent(Event event) throws IdentityEventException {
// Validate the password age with min age configured
}
#Override
public String getName() {
return "passwordMinAge";
}
#Override
public String getFriendlyName() {
return "Password Minimum Age";
}
#Override
public String getCategory() {
return "Password Policies";
}
#Override
public Map<String, String> getPropertyNameMapping() {
Map<String, String> nameMapping = new HashMap<>();
nameMapping.put(PasswordMinAgeConstants.PM_MIN_AGE_ENABLE, "Enable Password Minimum Age Feature");
nameMapping.put(PasswordMinAgeConstants.PW_MIN_AGE_COUNT, "Password Minimum Age (Days)");
return nameMapping;
}
#Override
public void init(InitConfig configuration) throws IdentityRuntimeException {
super.init(configuration);
IdentityPasswordMinAgeServiceDataHolder.getInstance().getBundleContext().registerService
(IdentityConnectorConfig.class.getName(), this, null);
}
public Properties getDefaultPropertyValues(String tenantDomain) throws IdentityGovernanceException {
Map<String, String> defaultProperties = new HashMap<>();
defaultProperties.put(PasswordMinAgeConstants.PM_MIN_AGE_ENABLE, configs.getModuleProperties()
.getProperty(PasswordMinAgeConstants.PM_MIN_AGE_ENABLE));
defaultProperties.put(PasswordMinAgeConstants.PW_MIN_AGE_COUNT, configs.getModuleProperties()
.getProperty(PasswordMinAgeConstants.PM_MIN_AGE_ENABLE));
Properties properties = new Properties();
properties.putAll(defaultProperties);
return properties;
}
}
Make this class an OSGi bundle and register the PasswordMinAgeValidationHandler as AbstractEventHandler
protected void activate(ComponentContext context) {
try {
BundleContext bundleContext = context.getBundleContext();
IdentityPasswordMinAgeServiceDataHolder.getInstance().setBundleContext(bundleContext);
PasswordMinAgeValidationHandler handler = new PasswordMinAgeValidationHandler();
context.getBundleContext().registerService(AbstractEventHandler.class.getName(), handler, null);
} catch (Exception e) {
log.error("Error while activating identity governance password min age component.", e);
}
}
Deploy the jar in IS_HOME/repository/components/dropins
Add the following configurations in the IS_HOME/repository/conf/identity/identity-event.properties
module.name.13=passwordMinAge
passwordMinAge.subscription.1=PRE_UPDATE_CREDENTIAL
passwordMinAge.subscription.2=PRE_UPDATE_CREDENTIAL_BY_ADMIN
passwordMinAge.enable=false
passwordMinAge.count=5
Restart the IS server
In the Resident Identity Provider configuration -> Password Policies, enable both Password History and Password Minimum Age features.
Here you can find the complete source code

AWS Cognito User Pool Sign In Missing Authentication Token

I am trying to authenticate my user in a Xamarin Forms cross platform app using AWS Cognito User Pools.
I am able to sign up a user using the SignUpAysnc() and I can see it populate in the user pool in the AWS console.
CognitoUserPool userPool = AmazonUtils.UserPool;
Dictionary<string, string> userAttributes = new Dictionary<string, string>();
userAttributes.Add("email", email);
userAttributes.Add("given_name", given_name);
userAttributes.Add("family_name", family_name);
userAttributes.Add("gender", gender);
userAttributes.Add("birthdate", birthdate);
userAttributes.Add("address", address);
userAttributes.Add("locale", locale);
userAttributes.Add("phone_number", phone_number);
await userPool.SignUpAsync(email, Password, userAttributes, null);
However when I try to use the email and password provided to sign in I keep getting this exception:
[0:] Missing Authentication Token
My current authentication code is:
private async void LoginButton_Clicked(object sender, EventArgs e)
{
AdminInitiateAuthRequest authRequest = new AdminInitiateAuthRequest();
authRequest.ClientId = Constants.ClientID;
authRequest.AuthParameters.Add("email", "test.user#email.com");
authRequest.AuthParameters.Add("password", "Password12!");
authRequest.UserPoolId = Constants.AuthPoolID;
authRequest.AuthFlow = AuthFlowType.ADMIN_NO_SRP_AUTH;
try
{
AdminInitiateAuthResponse response = await AmazonUtils.IdentityClientProvider.AdminInitiateAuthAsync(authRequest);
}
catch(Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
Does anyone know what I might be missing?
The thing is that you need to initiate the authentication challenge first, and then pass password as well as encrypted string, that contains pool name, username, secret block and other information.
This is a good .Net example: http://blog.mmlac.com/aws-cognito-srp-login-c-sharp-dot-net/
Note that you need to add Org.BouncyCastle.Math and Org.BouncyCastle.Security via NuGet to your project in order to compile it.
There is another example: https://gist.github.com/dbeattie71/44ea3a13145f185d303e620c299ab1c5
It looks promising, but I did not check it so I can't guaranty that it works. From it you could get an understanding on how overall process looks like.

WSO2 User self registration

I am trying to call the WSO2 Identity server web service using a java client.
public static void main(String[] args) {
UserInformationRecoveryService service = new UserInformationRecoveryService();
UserInformationRecoveryServicePortType port = service
.getUserInformationRecoveryServiceHttpsSoap11Endpoint();
BindingProvider prov = (BindingProvider) port;
prov.getRequestContext()
.put(BindingProvider.USERNAME_PROPERTY, "admin");
prov.getRequestContext()
.put(BindingProvider.PASSWORD_PROPERTY, "admin");
try {
List<UserIdentityClaimDTO> list = port
.getUserIdentitySupportedClaims("http://schemas.xmlsoap.org/ws/2005/05/identity");
System.out.println(port
.registerUser("user96", "Asdf#234", list, "profile", "")
.getUserId().getValue());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
When I pass in password not matching the password criteria, I can see the error message in WSO2 logs:
Password pattern policy violated. Password should contain a digit[0-9], a lower case letter[a-z], an upper case letter[A-Z], one of !##$%&* characters
But when the password is compliant, I just get an error
org.wso2.carbon.identity.mgt.services.UserInformationRecoveryServiceIdentityMgtServiceException_Exception: Error occurred while adding user : user96
Nothing in WSO2 log and the user is not added. Any clue as to what is wrong here?
Better enable debug logs in the log configuration file.
[IS_Home]/repository/conf/log4j.properties
Add the following entry
log4j.logger.org.wso2.carbon.user.core=DEBUG
This will give the debug logs which will help to understand the issue

wso2is: how to register a UMListenerServiceComponent?

I would like to re-distribute events in the IS management console. For example if I add/change/delete a user or a role I would like to re-send these updates to other consumers.
The only way I found until now is the UMListenerServiceComponent.
It looks like I can define my own UserStoreManagerListener and register it at the UMListenerServiceComponent.
The following example is from
https://svn.wso2.org/repos/wso2/branches/carbon/3.2.0/core/org.wso2.carbon.user.core/3.2.3/src/main/java/org/wso2/carbon/user/core/jdbc/JDBCUserStoreManager.java
In this case the action of adding a user is triggering the registered listeners.
public void addUser(String userName, Object credential, String[] roleList,
Map<String, String> claims, String profileName, boolean requirePasswordChange)
throws UserStoreException {
for (UserStoreManagerListener listener : UMListenerServiceComponent
.getUserStoreManagerListeners()) {
if (!listener.addUser(userName, credential, roleList, claims, profileName, this)) {
return;
}
}
// persist the user info. in the database.
persistUser(userName, credential, roleList, claims, profileName, requirePasswordChange);
}
My question is how can I implement and register this kind of listeners?
Or is there an easier way?
Thanks in advance!
Problem solved!
Downloaded the identity-manager version which is used for the wso2IS 4.6.0:
http://svn.wso2.org/repos/wso2/carbon/platform/branches/turing/components/identity/org.wso2.carbon.identity.mgt/4.2.1
The class IdentityMgtServiceComponent is registering the IdentityMgtEventListener as an service in the Osgi-Context.
IdentityMgtServiceComponent:
protected void activate(ComponentContext context) {
listener = new IdentityMgtEventListener();
serviceRegistration = context.getBundleContext().registerService(
UserOperationEventListener.class.getName(), listener, null);
Finally I copied this pattern and wrote my own bundle with an extension of AbstractUserOperationEventListener and activated it via a bundle-loader-class.
All the pre/post add/delete actions are triggered fine.
Hope this helps

ServiceStack web services security

Hi I am new to working with Servicestack and have downloaded their very comprehensive bootstrapapi example and am working with it, but am still having some issues. The issue is with security, what is happening is I am getting 405 errors when trying to access the protected services. Using the authenticate service it appears that I am authenticating correctly. Please help and explain. Here is the code:
public class Hello
{
public string Name { get; set; }
}
public class AuthHello
{
public string Name { get; set; }
}
public class RoleHello
{
public string Name { get; set; }
}
public class HelloResponse
{
public string Result { get; set; }
}
The Services:
public class HelloService : ServiceBase<Hello>
{
//Get's called by all HTTP Verbs (GET,POST,PUT,DELETE,etc) and endpoints JSON,XMl,JSV,etc
protected override object Run(Hello request)
{
return new HelloResponse { Result = "Hello, Olle är en ÖL ål " + request.Name };
}
}
[Authenticate()]
public class AuthHelloService : RestServiceBase<AuthHello>
{
public object Execute(Hello request)
{
return new HelloResponse { Result = "Hello, " + request.Name };
}
}
[RequiredRole("Test")]
public class RoleHelloService : RestServiceBase<RoleHello>
{
public object Execute(Hello request)
{
return new HelloResponse { Result = "Hello, " + request.Name };
}
}
Here is the AppHost:
public class HelloAppHost : AppHostBase
{
//Tell Service Stack the name of your application and where to find your web services
public HelloAppHost() : base("Hello Web Services", typeof(HelloService).Assembly) { }
public override void Configure(Container container)
{
//Register all Authentication methods you want to enable for this web app.
Plugins.Add(new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] {new CustomCredentialsAuthProvider(), //HTML Form post of UserName/Password credentials
}));
container.Register<ICacheClient>(new MemoryCacheClient() { FlushOnDispose = false });
//register user-defined REST-ful urls
Routes
.Add<Hello>("/hello")
.Add<Hello>("/hello/{Name}")
.Add<AuthHello>("/AuthHello")
.Add<RoleHello>("/RoleHello");
}
}
UPDATE
Everything works as expect if you replace : RestServiceBase with : ISevice so now the question is why.
Check the wiki documentation first
I would first go through the documentation in ServiceStack's Authentication Wiki to get a better idea about how ServiceStack's Authentication works. There's a lot of documentation in the wiki, so if you're unsure of something you should refer to that first. It's a community wiki so feel free to expand whats there if you think it can help others.
Refer to the implementation in the source code if behavior is not clear
If you're unsure of what something does you should refer to the RequiredRole source code as the master authority as how it works. RequiredRole is just a Request Filter Attribute which gets run before every service that has the attribute.
The RequiredRole attribute just calls your session.HasRole() method as seen here:
public bool HasAllRoles(IAuthSession session)
{
return this.RequiredRoles
.All(requiredRole => session != null
&& session.HasRole(requiredRole));
}
Because it just calls your session you can override the implementation of session.HasRole() if you have a custom session.
Registering and Implementing a CustomUserSession
The Social BootstrapApi project does implement its own CustomSession that it registers here but does not override the HasRole() implementation so it uses the built-in implementation in the base AuthUserSession.HasRole() which simply looks like the Roles collection to see if the user has the specified role in their Session POCO:
public virtual bool HasRole(string role)
{
return this.Roles != null && this.Roles.Contains(role);
}
Session properties populated by AuthUserRepository
The Roles property (as well as most other properties on a users Session) is populated by the AuthUserRepository that you have specified e.g. if you're using the OrmLiteAuthRepository like SocialBootstrapApi does here than the Roles attribute is persisted in the Roles column in the UserAuth RDBMS table. Depending on the AuthUserRepository you use the UserAuth / UserOAuthProvider POCOs get stored as RDBMS tables in OrmLite or as text blobs in Redis, etc.
Manage roles and permissions with AssignRoles / UnAssignRoles services
So for a user to have the required role (and authorization to pass), it should have this Role added to its UserAuth db row entry. ServiceStack's AuthFeature includes 2 services for managing users permissions and roles:
/assignroles
/unassignroles
How to initially give someone the Admin Role
These services does require a user with the Admin Role to be already authenticated.
You can do this by manually changing a specific users UserAuth.Role column to include the value "Admin". The Social Bootstrap API project instead does this by handling the OnAuthenticated() event on its CustomUserSession that simply checks to see if the authenticated username is declared in the Web.Config and if it is, calls the AssignRoles service giving that authenticated user the Admin Role:
if (AppHost.Config.AdminUserNames.Contains(session.UserAuthName)
&& !session.HasRole(RoleNames.Admin))
{
var assignRoles = authService.ResolveService<AssignRolesService>();
assignRoles.Execute(new AssignRoles {
UserName = session.UserAuthName,
Roles = { RoleNames.Admin }
});
}