Jump to content
We've recently updated our Privacy Statement, available here ×
  • Adding email address and other properties to users via SSO customizations


    Michael Bielkiewicz
    • Features: JasperReports Server, User Authorization Version: v8, v7, v6 Product: JasperReports® Server

    When implementing custom Single Sign-On with TIBCO JasperReports® Server using the preAuth Token method, certain user objects are already included for you however sometimes you may want to include other properties such as email address or the user's full name. To do this requires creating custom Java code, however the Jaspersoft engineers have provided a hook method to make this slightly simpler than starting from scratch.

    For this article, we will focus on the preAuth Token method of SSO, however the same general principles apply to any SSO method that makes use of the ExternalUserProcessor code.

    See this video about preAuth Token setup in general: https://youtu.be/sikZETuPBr8

    single-sign-on_-_pre-authenticated_tokens.jpg.37e607fc62bd05b1e2d7753ec173d1aa.jpg

    Since we will be making custom code changes, you may want to go over this article if you haven't customized code for JasperReports® Server before.

    You will need to customize the ExternalUserSetupProcessor class found in the com.jaspersoft.jasperserver.api.security.externalAuth.processors package of the source code. We recommend copying this class into your own custom package (i.e. com.jaspersoft.ps.sso) and naming it something different (CustomExternalUserProcessor.java) to help differentiate it when we update the XML file later.

    Another option is to simply extend the base class and implement the method we will update below, but for Multi-Tenant implementations, there is already a class that extends this that you must also extend (com.jaspersoft.jasperserver.multipleTenancy.security.externalAuth.processors.MTExternalUserSetupProcessor) should you want to extend and not fully replace this code. If you have other customizations to this class, sometimes it's just easier to replace the whole class as mentioned in the previous paragraph.

    As you probably know, during a default token-based call, data is passed to JasperReports Server using key/value pairs as defined in the applicationContext-externalAuth-preAuth-mt.xml file like so:

    <entry key="username" value="u" />
    <entry key="roles" value="r" />
    <entry key="orgId" value="o" />
    <entry key="expireTime" value="exp" />
    <entry key="profile.attribs" >
        <map>
            <entry key="profileAttrib1" value="pa1" />
            <entry key="profileAttrib2" value="pa2" />
        </map>
    </entry>

    We need to obtain the additional details such as email address and full name also via the token. I recommend using "e" for email address and "f" for full name. You do not need to define these in the xml file however. You can simply add them to the URL string when making the SSO call to JasperReports Server.

    u=obama|r=PRESIDENT,HUSBAND|o=WhiteHouse|pa1=USA,Kenya|pa2=Washington|e=president@somebighouse.gov|f=Barack Obama

    (Note: We always recommend to URL encode your full string so special characters such as equals (=), pipe (|), and spaces get translated and sent through properly)

    Now we need to get that extra data and add it to the user's account when they are synced into JasperReports Server. So let's move back into the custom Java code.

    The method you need to implement is called updateUserAttributes. Note the comment: 

    /**
     * A 'hook' method to extend when additional user columns need to be populated (e.g. emailAddress)
     *
     * @param user
     */

    As you can tell, this method was put in place for this explicit operation of adding data to the user object. The trick is how to get your data from the SSO process into this method. In this class, you have access to the External Auth Details. To get a handle on this, you need to do this:

    ProcessorData processorData = ProcessorData.getInstance();
    ExternalUserDetails userDetails = (ExternalUserDetails) processorData.getData(EXTERNAL_AUTH_DETAILS);
    

    Once you have a handle on the external details, you now need to get the extra attributes we placed on the URL. Jaspersoft places any parameters that aren't defined in the XML file into a Map containing the key/value pairs from the URL.

    Once you have the ExternalUserDetails object above, you can obtain the additional parameters with the following call:

    Map<String, String> unmappedParams = (Map<String, String>) userDetails.getAdditionalDetailsMap().get(ExternalUserDetails.UNMAPPED_PARAMS_MAP_KEY);
            
    String userEmailAddress = unmappedParams.get("e");        
    String userFullName = unmappedParams.get("f");

    Now that you have the data from the URL, you simply add them to the User object that was passed into this method:

    user.setEmailAddress(userEmailAddress);
    user.setFullName(userFullName);

    And that's it! Compile your custom code into a JAR file, modify your external auth XML file to point to your custom class:  

    <bean id="mtExternalUserSetupProcessor" class="com.jaspersoft.ps.sso.CustomMTExternalUserProcessor" parent="abstractExternalProcessor">

    ...restart your server, and test!

    Note that in the example above I pointed to CustomMTExternalUserProcessor (and not CustomExternalUserProcessor). Since there's an additional layer for Multi Tenant implementations, I also created a custom version of the MT External User Processor class but it's only modification is to extend my CustomExternalUserProcessor. This is personal preference as you can extend the base class and add the method we customized above, but I tend to have other modifications in this class that don't always allow for a simple override.

    Here is our full, custom version of the updateUserAttributes method:

    protected void updateUserAttributes(User user) {
        //MJB added the lines in this method to show example of passing other stuff in token
        ProcessorData processorData = ProcessorData.getInstance();
        logger.debug("Inside updateUserAttribute override, about to extract user details");
        ExternalUserDetails userDetails = (ExternalUserDetails) processorData.getData(EXTERNAL_AUTH_DETAILS);
    
        logger.debug("Inside updateUserAttribute override, username: " + userDetails.getUsername());
        Map<String, String> unmappedParams = (Map<String, String>) userDetails.getAdditionalDetailsMap().get(ExternalUserDetails.UNMAPPED_PARAMS_MAP_KEY);
    
        String userEmailAddress = unmappedParams.get("e");
        logger.debug("emailAddress from additional params map: " + userEmailAddress);
    
        String userFullName = unmappedParams.get("f");
        logger.debug("fullName from additional params map: " + userFullName);
    
        user.setEmailAddress(userEmailAddress);
        user.setFullName(userFullName);
        //MJB end added lines
    }

    Note the additional debug log statements. You can always add any class (reference the fully qualified class name) into your Manage --> Server Settings --> Log Settings page on JRS as Superuser and your log statements will be output to your jasperserver.log file for easier debugging.


    MJB

    Update 2020-06-12 – see also an example of custom folder processor that can use (for other purposes) some of the Org / User properties provided by the token: https://community.jaspersoft.com/wiki/example-custom-user-folder-processor-jasperreports-server


    User Feedback

    Recommended Comments

    There are no comments to display.



    Create an account or sign in to comment

    You need to be a member in order to leave a comment

    Create an account

    Sign up for a new account in our community. It's easy!

    Register a new account

    Sign in

    Already have an account? Sign in here.

    Sign In Now

×
×
  • Create New...