Zowe: Full Stack Programming on the Mainframe
{Core} One of the benefits of working on The Open Mainframe Project’s Zowe is being able to work across the full stack. In this post I’m going to give an example of working across different parts of the stack to implement a new feature to the Zowe Application Framework, the ability to change your z/OS password.
A rough diagram of the Zowe Application Framework Stack can be seen below.
The top of the stack consists of different applications running within the application manager which can be considered as the desktop of the Zowe Application Framework. These applications can be Angular, React, or iFrame applications and consist of their own back-end. The next step down is the ZLUX app manager written in mostly Angular, which manages the different running applications. The app manager then connects to the ZLUX server framework, the node server for the Zowe Application Framework. The node server and app manager are then able to communicate to z/OS by connecting to a ZSS (Zowe Secure Services) server which makes use of a shared library called ZCC (Zowe Common C); both are primarily written in C with some Metal C, and even some assembly. Although the Zowe Application Framework is built to be able to handle many different authentications and back-end servers, such as ZOSMF and APIML, we are going to focus on the ZSS server in this post.
We are going to begin at the bottom of the stack, in the C code of Zowe Common C and work our way up the stack. To start we need to first figure out how we are going to change the password. Luckily IBM has public documentation for different assembler callable services for the z/OS UNIX System Services (z/OS UNIX). Going through the documentation we can see that they provide a call for both 31-bit and 64-bit systems to change the password BPX1PWD and BPX4PWD respectively.
Now that we know at a low level how we can change the password on a z/OS system, we can start implementing the feature. Since the password is account information we can start by implementing a wrapper function for these calls in zosaccounts.c in the zowe-common-c repo, which is a shared C library used by ZSS. Since IBM provides calls for both 31-bit and 64-bit that take in the same parameters, we can create a macro for our service call using predetermined macros, such as _LP64.
Now that we have our macro, we can define a wrapper function that will call this service. By looking at the documentation we can see the BPXPWD calls take a username, current password, new password, and each respective length. Since we can determine the length within our wrapper function, it can just take in the username, current password, and new password and then extract all the information needed by the BPXPWD service calls.
The full code can be seen here.
Now that we have our wrapper function for the service call, we can move up the stack to the ZSS code and create our endpoint that calls the wrapper function we just made. Since we are dealing with the authentication of the user we will add our endpoint to the AuthService.c file in ZSS.
This function needs to parse and sanitize the data that will be sent over in the body of the HTTP request because we don’t want to send any null values to the BPX assembler services we called in the wrapper function. The BPX commands provided by IBM will give us return codes once they’re called to indicate how the operation went. We can find a list of the different return codes here. With the return codes, we can map them to proper responses to send from the endpoint we are making.
For example, we can see that return code 111 means permission denied which means the password provided to this BPX call is incorrect so we can define different macros for the return codes and create a switch statement that will translate the return codes into proper responses like so.
We can then test all different cases and compare the return codes to the documentation to create responses to ensure accurate information to the user. With all the responses we can then fill out the rest of the cases in the switch statement. The full code can be seen here.
Now that we have our function, we can install it as an endpoint to the ZSS server. To do so, we need to create the HTTP service and define the values for it — the route, the function, and the authorization type.
Below you can see an example of us defining the /password route to call our function.
We set the authentication type to none since we want this password reset option to be available for when the user’s password has expired and they are unable to authenticate themselves.
Now that we have our service installation function we just need to call it in the main ZSS function, which installs all the services. However, since we only want this available for z/OS systems we check before we install it like so.
The full code can be seen here and now we have our endpoint on ZSS to change a z/OS user’s password.
Now that we have our endpoint, we can start moving further up the stack to the node server, which includes the ZLUX server framework and the ZSS authentication handler for the server framework. Since Zowe is designed to work with many different authentication services, not just ZSS, such as z/OSMF, we need to add our endpoint to the ZSS authentication handler.
Each authentication handler is defined with capabilities that the node server checks when it tries to perform actions, so we need to define a canChangePassword capability along with our new function which will simply just call the ZSS endpoint we have created.
The full code can be seen here.
Now that our ZSS handler has the capability and function to change the password, we can add this function to our node server.
We need to define a function in our web authentication file that checks all the installed authentication handlers to see if they have the canChangePassword capability. If the capability is present, we can then call the function to change the password. Since at this time, only one handler can change the password, we can return once we found a handler with the capability. If no handlers with the capability are found, we can throw an error. The full code for this function can be seen here.
Now that we have the “password reset” function in our web authentication file we just need to install the function in our web application like below.
The full implementation can be seen here.
Once our service is on our node server, we can move up the stack again to the ZLUX app manager and implement the new UI changes to the desktop allowing users to change their passwords.
Since the user will want to change the password immediately after they attempt to login with an expired password we can use the existing login page and alter it for that case. To do so, we need to know when we want to show the login page and what form to show. To do so we can leverage the loginScreenChangeVisibility emitter in the authentication manager service. There currently exists UserLogin, UserLogout, and SessionExpire events. However, we can add a few more such as PasswordChange, PasswordChangeSuccess, and HidePasswordChange to indicate when we want to show and alter the login page form.
This is the default login page.
Now if the user logs in and we get a response saying the users password is expired we can alter the screen’s forms and image to look like this.
Now we can leverage the notification manager in the desktop once the user has logged in to indicate to the user that they have successfully changed the password.
Now if users want to change their password at will, we can add a tool shortcut to the personalization panel; tool icon in the bottom right of the desktop.
And create a change password option that triggers the PasswordChange event which we can listen to show and alter the login page to show a password reset form.
We also need to make sure to display proper errors for the user if they are inputting incorrect information. Luckily, we set the response of the endpoint we created on ZSS to have the response messages for us so we can just check and display those responses.
The full code changes in the authentication manager can be found here, the full changes to the personalization panel can be found here, and the full changes for the login page can be found here.
Now that we have completed the UI changes for the password reset, we are essentially done with this new feature. Hopefully, now you can start contributing across the stack to the Zowe Open Mainframe Project.
Click the links to learn more about Zowe and more Zowe blogs.