Keycloak user attributes with multiple values (list) - customization

I'm having a Keycloak use case where single user may have multiple customer numbers. These customer numbers would need to be sent to service provider / client and also be easily updated by administrators. Some users may have hundreds of customer numbers. Currently I'm using single user attribute named "customerNumbers" where the customer numbers are separated by comma but I'd like:
To offer the administrators possibility to see each customer number in its own field
To send the customer numbers as an JSON array instead of comma separated claim
So instead of this:
I'd like something like this:
And instead of this
"customers": {
"customerNumbers": "140661,140662"
},
I'd like something like this:
"customers": [
{"customerNumber": "140661"},
{"customerNumber": "140662"}
],
How should one approach this kind of situation?

Keyclaok use a custom format to save multiple value in the same field by separating multiple value with ##
key: customerNumbers value: 140661##140662
if you want to show that field on your jwt access token you can do it by creating a client scope -> protocol mapper (user attribute) for custom attribute making sure to set multivalued on
set custom attribute on protocol mapper:
After that you can add those mapper to your client so it will appear on your access token
set custom attribute on jwt token:

You need to add your values in the user attributes like this [{"customerNumber": "140661"}, {"customerNumber": "140662"}]
ie [Keycloak user management, attributes tab][1]
your client mapper will need be like this (i think i tried every other option)
enter image description here

Related

DynamoDB table design for social network

I got a thinking-problem in DynamoDB.
My structure is looking as following:
primary key = "id"
sort key = "sort"
I have posts, users and "user A following user B" relationships.
Users:
id=1234
sort="USER_USER_1234"
name="max" (for example)
-
id=3245
sort="USER_USER_3245"
name="tom"
Post:
id=9874
sort="POST_POST_1234 (because its created by user id 1234)
createdAt=1560371687
Following:
id=1234
sort="USER_FOLLOW_3245"
--> tom follows max (but max not tom)
How could I design a query to get all posts by the people which tom(id=3245) is following? So in my case the post id 9874?
My approach was to put a GSI where sort is the primary key and id is the sort key (that i can query all people which user A is following), than get all the posts from the users (with help of the same GSI) and sort the result after a second index where createdAt is the sort key. The problem is that this needs much much querys (imagine user A would follow 10000 people and they all make posts). Is there a technique or design thinking approach which you could recommend for this situation? My second approach was to index the whole application table to elastic search and do a nested query. Would this make more sense? Or would you recommend using another type of database like AWS neptune?
There's a hands-on lab on aws about a similar problem - "a mobile application that includes a social network": https://aws.amazon.com/getting-started/hands-on/design-a-database-for-a-mobile-app-with-dynamodb/4/
Brief description:
Users will upload photos through your application
users will want to find and follow friends
By following a friend, a user will receive notifications of the friend’s new photos
user will be able to message their friends
friends can view their photos
users can react to a photo with one of four emojis — a heart, a smiley face, a thumbs up, or a pair of sunglasses.
When looking at a photo, users should be able to see the number of each type of reaction a photo has received
The model has the following entities: User, Photo, Reaction, Friendship.
A User can have many Photos, and a Photo can have many Reactions. Finally, the Friendship entity represents a many-to-many relationship between Users, as a User can follow multiple Users and be followed by multiple other Users.
Access patterns
Based on the business requirements, these are the access patterns identified:
User
Create user profile (Write)
Update user profile (Write)
Get user profile (Read)
Photo
Upload photo for user (Write)
View recent photos for user (Read)
React to a photo (Write)
View photo and reactions (Read)
Friendship
Users can follow friends, view updates on their friends’ activities, and receive recommendations on other friends they may want to follow.
A friendship is a one-way relationship, like Twitter. One user can choose to follow another user, and that user may choose to follow the user back. For our application, we will call the users that follow a user “followers”, and we will call the users that a user is following the “followed”.
Based on this information, we have the following access patterns:
Follow user (Write)
View followers for user (Read)
View followed for user (Read)
On the Friendship entity, we have an access pattern that needs to find all users that follow a particular user as well as an access pattern to find all of the users that a given user follows.
Table Design
Because of this, we’ll use a composite primary key with both a PK and SK value. The composite primary key will give us the Query ability on the PK to satisfy one of the query patterns we need:
Entity PK SK
User USER#<USERNAME> #METADATA#<USERNAME>
Photo USER#<USERNAME>. PHOTO#<USERNAME>#<TIMESTAMP>
Reaction REACTION#<USERNAME>#<TYPE> PHOTO#<USERNAME>#<TIMESTAMP>
Friendship USER#<USERNAME> #FRIEND#<FRIEND_USERNAME>
The Friendship entity uses the same PK as the User entity. This will allow you to fetch both the metadata for a user plus all of the user’s followers in a single query:
KeyConditionExpression="PK = :pk AND SK BETWEEN :metadata AND :photos",
ExpressionAttributeValues={
":pk": { "S": "USER#{}".format(username) },
":metadata": { "S": "#METADATA#{}".format(username) },
":photos": { "S": "PHOTO$" },
},
A secondary (inverted) index is useful to query the “other” side of a many-to-many relationship. This is the case for your Friendship entity. With your primary key structure, you can query all followers for a particular user with a query against the table’s primary key. When you add an inverted index, you will be able to find the users that a user is following (the “followed”) by querying the inverted index:
KeyConditionExpression="SK = :sk",
ExpressionAttributeValues={
":sk": { "S": "#FRIEND#{}".format(username) }
},
Extensions
What would be interesting is to tweak the design to support mega-popular users (having millions of followers).
Another interesting access pattern not mentioned here is the user feed - see all the photos that their friends have recently posted. This could be done with another table to contain this stream of data which gets updated whenever a friend posts something (find his followers, update their feeds...).
In Amazon Neptune, this would be something as simple as:
g.V(3245).E('post')
The above query would return an iterator, to all the vertices connected by the Edge label "post", starting from the vertex with ID "3245". You can firther tighten it up by either projecting specific properties (.property('name')) from those vertices or materializing the whole vertex (.valueMap()). This is just Gremlin syntax, and you can easily do the same using SPARQL as well, and Amazon Neptune supports both of them.
A bigger question for you is to evaluate all the types of queries you wish to perform on your data, and see if modeling it in a graph database makes sense. If it does, then you're better off using Neptune as opposed to something custom using a mix of other products. Querying/Traversing highly connected data, navigating through relationships etc are some of the classic usecases to use a graph data model.

Custom authorization for pages in oracle apex

How can I create an authorization schema for pages?
For example: I have
pages like page1, page2, page3 and page4 with
users as user1, user2, user3 and user4.
When I login
user1 should get only page1 and page4
user2 --> page2 and page3
user3 --> page1 and page3
user4 --> page2 and page4
I.e in a priv table the page numbers and the users are stored. The boolean return value function is working for components, but for the page it shows an error.
How can I write an authorization schema for the above roles?
1 - Go to Shared Components
2 - Click on Authorization Schemes
3 - Create a new scheme of the type "PL/SQL function returning boolean"
4 - Your function should return "false" to denied access
In this pl/sql code you have access to :APP_USER variable and :APP_PAGE_ID (page number).
If you have a function that receives the user and the page and return a boolean checking if he has or no access, so just do:
BEGIN
RETURN MYFUNCTION(:APP_USER, :APP_PAGE_ID);
END;
5 - Go to "Edit Application Properties" > "Security" and choose your
authorization scheme.
6 - You don't need to set for every page the authorization scheme, just do the step 5.
I don't know how is your table. But supposing that it's have two columns like
USER PAGE_NUMBER
user1 1
user1 4
user2 2
user2 3
user3 1
user3 3
user4 2
user4 4
So your function look like this:
CREATE OR REPLACE FUNCTION "MYFUNCTION" (p_user IN VARCHAR2, p_page_number IN NUMBER)
RETURN BOOLEAN AS
v_count NUMBER := 0;
BEGIN
SELECT count(*) INTO v_count
FROM mytable
WHERE user = p_user AND page_number = p_page_number;
IF v_count = 0 THEN
RETURN false;
END IF;
RETURN true;
END;
You should consider a custom Authorization Scheme&Authentication Scheme..
1- Create a table for the users to store each user name and password and put a column for 'user_type', in this column you will have the types of users you have for example: 'dev' for developer and 'adm' for admin ans so on ...
2- Create an plsql function that returns a Boolean (true/false) based on
a query that compares the user name and password you get from the user with the ones stored at your users table.
This function will also set 'Session Variables' to pass the user_name and
user_type after a successful login, something like:
apex_util.set_session_state('SESSION_U_TYPE',temp_type);
apex_util.set_session_state('SESSION_USER_NAME',in_username);
3- At the shared components of your application create 'Application Items' by the same exact names you use in your function (here SESSION_U_TYPE, SESSION_USER_NAME)
4- Edit your 'Log-In' page and remove or comment out the default code and use your function and pass the user_name and password via binding variables
5-Now go to shared components again and create a custom Authorization Scheme, give it a name and choose 'SQL exist' as type and write a sql
query to check the user_type of the current user, something like:
SELECT * FROM my_users
WHERE user_name = :SESSION_USER_NAME AND user_type = 'dev';
Repeat this step to create as many 'access levels' as you need
6- Finally, go to each page and under security section choose the
scheme or the user level you want to allow to access this page
-- Notes:
This is fast solution (but working fine) and you can add many improvements to it for example you should create a procedure to handle the log-in and pass the parameters to the authentication function
YOU HAVE TO HASH THE PASSWORD AS YOU SHOULD NEVER STORE PASSWORD IN PLAIN TEXT!
I hope this was useful
The above authorization schema with return boolean function works for components if we save the component id along with the page id and check for components
But for page authorization its not working and showing error.
tested with the above table structure and function
enter image description here

apex5.1, how to set custom login page

I need to set a custom page login in apex5.0
If login is invalid, the standard error msg should be displayed.
However, i have a table that contains an expiry date for the user. I want to add a check user is expired then he should not login the system and message 'No access' displayed. if sys_date > expiry_date.
How is it possible to do that?
The best way to do this is to create your own authentication scheme.
Create your own function which checks if username and password match with your user table, and then check if expiry_date > sysdate. Add a new authentication scheme (shared components -> authentication schemes -> create and select custom as the scheme type. Then add your function in there.

WSO2 IS SCIM user schema extension. How to define and map multi-valued attributes

We are using WSO2 IS 5.1 and I'd like to define multi-valued attribute:
....
{
"attributeURI":"urn:scim:schemas:extension:wso2:1.0:wso2Extension.vultPerson.mailAlternateAddress",
"attributeName":"mailAlternateAddress",
"dataType":"string",
"multiValued":"true",
"multiValuedAttributeChildName":"null",
"description":"Some attribute",
"schemaURI":"urn:scim:schemas:extension:wso2:1.0",
"readOnly":"false",
"required":"false",
"caseExact":"false",
"subAttributes":"null"
},
...
I mapped this attribute in urn:scim:schemas:core:1.0 dialect to LDAP (primary user store) atrribute mailAlternateAddress (my LDAP has this attribute in one of UserEntryObjectClass'es). I tried to provision user by SCIM API. User was created, all simple attributes from extension were created too, only mailAltrernateAddress not. I tried to send this attribute as:
....
"mailAlternateAddress": [
{
"type": "work",
"value": "a.a"
}
....
and as:
...
"mailAlternateAddress": ["a.a","b.b"]
...
I received good responses to SCIM requests.
I tried mappings:
urn:scim:schemas:extension:wso2:1.0:wso2Extension.vultPerson.mailAlternateAddress -> mailAlternateAddress
and
urn:scim:schemas:extension:wso2:1.0:wso2Extension.vultPerson.mailAlternateAddress.work -> mailAlternateAddtress
Both with the same result.
BTW, according to core SCIM schema, emails attribute is mapped to LDAP mail attribute (this mapping is in WSO2 IS destribution) but this mapping doesn't work too, mail attribute isn't created.
What am I doing wrong?
One more question. Could I define canonical values for multi-valued attribute in scim-user-schema-extension?
The problem is in class
org.wso2.carbon.identity.scim.common.utils.AttributeMapper
There are strange limitations. At first I rewrote method getClaimsMap and now it works as expected.
I'm sorry for my English.

Sitecore ECM op-tin and opt-out roles dates

I want to know is there any way to get user subscrition / unsubscrition to email campaign ?
Is it saved in one of databases/tables in MSSQL ?
If you use the approach with opting in and out being determined on the fact if user is in role, then it is stored in the aspnet_UsersInRoles table in your core database. This table does not keep the information when role was assigned to the user. That's why you cannot get information when user subscribed or unsubscribed to email campaign.
The only thing you can check is if user is in the role:
user.IsInRole(roleName)
The user's subscription is driven by the users role, but It is possible to get the users subscriptions in ECM, You just have to use the api.
You can get the contact from the email address:
string fullName = commonDomain + "\\" + Util.AddressToUserName(username);
var contact = Contact.FromName(fullName);
var subscriptions = contact.GetSubscriptions();
Once you have a contact you can call the GetSubscriptions() method which will return the recipient lists the user is signed up to. There are a host of other methods you can call on a contact and if there is a a way to get the date unsubscribed/subscribed it will be here.
If not reflect Sitecore.EmailCampaign.dll and keep looking! There might be some extra information in the automation states table in the Analytics database. More info on automation state here:
https://www.sitecore.net/learn/blogs/technical-blogs/sitecore-magnified/posts/2013/09/ecm-automation-states-magic.aspx
Also noticed there is a method GetUnsubscribersStatistics on the Sitecore.Modules.EmailCampaign.Core.Analytics.AnalyticsHelper class. This will have the date of unsubscription.