Custom PAS plugin: How to render fullname of user stored in plugin via IPropertiesPlugin in personal bar?

The custom PAS plugin implements IExtractionPlugin, IAuthenticationPlugin and IUserFactoryPlugin using an external identity provider running the authentication and providing user data.
User data (user id, fullname, email) are stored in the custom PAS plugin by using IPropertiesPlugin via an OOBTree.

How to display the fullname stored in the plugin storage in personal bar viewlet?
Personal bar viewlet makes use of portal membership tool to get the member info:

...
membership = getToolByName(context, 'portal_membership')
member_info = membership.getMemberInfo(userid)
...
if member_info:
    fullname = member_info.get('fullname', '')

The user authenticated via the custom PAS plugin is not a portal member, so the viewlet falls back to the user id.

Is it a proper way to render the fullname in the viewlet to customize the viewlet and make use of the plugin's user properties?
Is there another / better way to render the fullname in the viewlet?

I believe (i.e. I am not sure) that the following may work:
PAS typically uses a so called PropertiedUser as class for user objects. As the name indicates, such a user can have properties provided by a "property PAS plugin". Let your plugin implement the corresponding interface and make the additional data available as properties of the user object.

Thank you very much for your answer!
The plugin makes already use of IUserFactoryPlugin, which uses a custom user derived from
Products.PlonePAS.plugins.ufactory.PloneUser, which is derived from from Products.PluggableAuthService.PropertiedUser.PropertiedUser.

...
    def createUser(self, user_id, name):
        # create a OIDCUser
        user_data = self._storage.get(user_id, None)
        if user_data is not None:

            print('OIDC CREATE USER USERDATA: ' + str(user_data))
            return OIDCUser(user_id, name)
        return None
...

'print' directive returns:

OIDC CREATE USER USERDATA: {'username': 'yRItPKlfaUDCOwrVkFlRzCaV2GYK-XGS-ooHcyAkVmk', 'fullname': 'Test fullname', 'roles': ['Test roles']}

IPropertiesPlugin seems to be ok too:

...
    def getPropertiesForUser(self, user, request=None):

        if not IOIDCUser.providedBy(user):
            return {}
        else:
            user_data = self._storage.get(user.getId(), None)
            if user_data is None:
                return {}

            print('OIDC USER PROPERTIES: ' + str(user_data))

            return user_data
...

'print' directive returns:

OIDC USER PROPERTIES: {'username': 'yRItPKlfaUDCOwrVkFlRzCaV2GYK-XGS-ooHcyAkVmk', 'fullname': 'My fullname', 'roles': ['My role]}

portal membership in the viewlet does not get a member based on the user id, so there is no member info. The user authenticated this way is not a portal member, so the properties are not asked.

I'm not aware, if there is a mechanism to solve my problem beside customizing the viewlet.
Any hints?

If the plugin implements Products.PluggableAuthService.interfaces,plugins.IPropertiesPlugin and returns a property sheet with the given property - and it is fetched before any other IPropertiesPlugin in the chain which may provide fullname ], it should appear on member_info.get('fullname', '').

Thank you very much for your answer!
Yes, IPropertiesPlugin is implemented and on top of the plugin chain.
After analyzing membership tool code it seems to be as follows:

Code in viewlet:

membership = getToolByName(context, 'portal_membership')
member_info = membership.getMemberInfo(userid)

Code in membership tool:

def getMemberInfo(self, memberId=None):
    if not memberId:
        member = self.getAuthenticatedMember()
    else:
        member = self.getMemberById(memberId)

getMemberById(memerId) returns None - probably the user is searched in acl_users. But there is no default Plone user object corresponding to the user id given by the identity provider - this is part of the requirements.

I came to the conclusion to customize the viewlet and use member = self.portal_state.member() to get the fullname - viewlet code:

...
if not self.anonymous:
    member = self.portal_state.member()
    ...
    user = member.getUser()
    fullname = user.getProperty('fullname', None)
....

Question: Why doesn't the viewlet make use of member to get the fullname? member.getUser() should return a proper user and it's properties (if implemented).
Thanks!

@dieter @jensens I missed to implement IUserEnumerationPlugin. getMemberById() loops over user enumeration plugins under the hood. So, all user data are rendered by Plone UI elements, no need to customize, the viewlet does its job now. Thanks again for your answers.

Plone Foundation Code of Conduct