Logout from the Controller level or remove current user from SecurityContext

Is there a way to logout a user programmatically from the Controller? or remove the current user from the SecurityContext?

29 comments

Yes, you will need to obtain WebLoginModel spring bean and call logout method.

0

Thanks for the quick response.  Lastly,  when a user click the logout link currently  it is redirecting to the login.html URL,  is it possible to redirect to another URL of my choosing?
I am authenticating with Siteminder and so when a user logout I want the user to be redirected to a Siteminder login page. BTW I am using a SiteminderLoginModule to authenticate
where it is getting the user credentials from the request header. Siteminder provides it's own logout URL which removes a session cookie as well. In essence I need to do a teamcity logout
plus additional Siteminder specific logout tasks.

0

Please see my last comment to the issue: http://youtrack.jetbrains.net/issue/TW-13660
In brief, in 6.0 it will be possible to provide custom url for the login page. Hope it helps.

0

Pavel,
          It is great that that functionality willl be available for 6.0 but unfortunately we need this functionality now.
Also in regards to using Siteminder to authenticate a logout URL is also provided that will remove a session cookie
from the session object just as Teamcity's logout URL removes a user from the SecurityContext. If Teamcity's authentication
is not being used then there should be a way to call a LogoutController where a programatic logout from Teamcity and Siteminder
can be done at the same time. Currently the logout URL only logout a user from Teamcity but user is still not logged out of Siteminder
as Sitemeinder session cookie is still present. All user credential needs to be removed.

I suspect that with a LogoutController removal of all user credential from the session can be acheived. So instead of the logout URL
making an Ajax call it should call a LogoutController instead, where the LogoutController is a custom controller that allows a developer
to programatically logout out a user from teamcity and any external authentication tool if needed.

0

In fact custom Login controller can easily remove all unnecessary cookies when user is redirected to it. So, for now, I do not see a necessity to provide control on logout function.
As for providing this functionality in 5.1, I doubt we'll be able to make an oficial release of 5.1 only because of this API change. Maybe you could use EAP build of TeamCity 6.0?
I know it is risky to use it for production (however it is stable enough and we do use it for our own server), but at least you could check whether this approach works for you.

We hope to produce TeamCity 6.0 EAP build which will have custom login page functionality by the end of this week.

0

Pavel,

Currently when you logout of Teamcity you are redirected to the login screen to log in again. With Siteminder authentication when you logout of Teamcity you will
be redirected to the Custom Login controller that will read the request header and find the user credential and forward the user to the projects page. I need a way of
knowing when a user is attempting to login vs logout of Teamcity in the custom controller so that I will know if I should remove the Siteminder session cookie or attempt to
login the user. How do I know when a user is logging out from the custom controller?

0

After the logout there won't be User object in the session. SessionUser.getUser(request) will return null. I think this can be used to check whether the logout actually happened. Note that there are cases when logout can be performed just because user session is expired and no handlers can be invoked at this time, so still even with some custom logout handler there can be situations when we won't be able to call it. To my opinion it is safer to check whether user is in the session or not. Without this check TeamCity willl redirect to the login page again.

0

Pavel thanks for your help with this matter. The problem I am having is my Custom Controller gets called every time a user tries to login or when the user tries to logout
since on logout Teamcity redirect back to the login page which calls the custom controller and at that point the SessionUser.getUser(request) will return null on login and logout
so this won't help me distinguish if the user is logging out or logging in.

0

Well, consider the following case: user removed SESSION_ID cookie from the browser, but left Siteminder cookie. Then he navigates to login page. In this case no one can tell whether user logged out via TeamCity or he just opens the page in the browser. I want to tell that it is practically impossible in some cases to distinguish whether login page was opened after the logout or not. Or in other words: we do not control how user logs out, and we can't control it.

I do not know how exactly you are solving this problem now with TC 5.1. But with 6.0 you'll be able to provide custom login page, which when opened checks whether a Siteminder cookie present and if so, performs logout, then allows user to log in.

0

Pavel:

When Siteminder is used to authenticate after user clicks the logout link the user will need to redirect to the Siteminder logout URL link as well.
The Siteminder agent running on the web server box will remove the session cookie. From Teamcity's prespective after a Teamcity logout is done
a way should be provided to call the Siteminder logout URL as well. I have an idea how I can do it.

Basically when a user is authenticated with Siteminder user credential is placed in the request header. The custom login controller will check the header
for the user credential and do a automatic Teamcity login if the user exist. So a successful login entail a sync between Siteminder authentication and Teamcity
login. In the custom controller this syncing means a user is successfully loged in so you can add an attribute to the session (siteminderTeamcitySync=true)
If the custom controller ever gets called for a given session again I assume the user is already logged out of Teamcity and so I will redirect to the Siteminder
logout URL so the session cookie can be removed and the Siteminder login page will be shown.


        HttpSession session = request.getSession(false);
        String siteminderTeamcitySyncString = (String)session.getAttribute(SITEMINDER_TEAMCITY_LOGIN_SYNC);
        
        /**
         * If siteminderTeamcitySyncString is true then user was successfully authenticated by Siteminder and
         * successfully synced with Teamcity for this session. The fact that this controller was called again
         * means that user was logged out of the Teamcity application and also needs to logout of Siteminder
         * (i.e. session cookie for Siteminder needs to be removed) so user will be redirected to Siteminder
         * logout URL.
         */
        if(siteminderTeamcitySyncString != null && siteminderTeamcitySyncString.equalsIgnoreCase("true")) {
            String redirectUrl = "https://siteminder.url@ge.com";
            return new ModelAndView(new RedirectView(redirectUrl));            
        }else{
               //attempt to login to teamcity
        }


if siteminderTeamcitySyncStringis null or false them the controller is being access for the first time which means user is attempting to login and
any other attempt to call the controller means user is logging out.

In theory this should work.

0

Sounds like this should work. If you need I can share a pre-EAP TC 6.0 build with custom login extension, so you would be able to check this approach.

0

Pavel,
If you can share a pre-EAP TC 6.0 with me I will take a look at it, thanks. I will also document all the Siteminder/teamcity code I developed
can give it to you. If this all works my company will use Teamcity as the defacto continuous integration tool. Teamcity is a great product
and it is being used by many groups but it can't go to production until it integrates with Siteminder which is used for authentication thoughtout
the company. I am determined to get it to work :-)

0

No problem, the build is uploaded to our FTP:
ftp://ftp.intellij.net/pub/.teamcity/custom_login/TeamCity-15598.exe

In your plugin you need to implement jetbrains.buildServer.controllers.login.LoginPageProvider
Then you can either make class implementing this interface a Spring bean (write it to the spring context xml), or you can register it using jetbrains.buildServer.ExtensionHolder.

0

Great! Is there any documentation or example?

0

Not yet, but if you did write some controllers or plugins for TeamCity, writing such extension should be easy.

0

Pavel, yes if it is implemented similiar to a regular plugin then I should be able to figure it out.
The ftp link is very slow.

0

Pavel I am not able to access the download ftp link, can you check to see it it is up?

0

Just checked, it works fine for me. I'll ask our admins to check accessibility of our ftp server tomorrow.

0

Thanks, I will try to access from home as well. Maybe it's a firewall issue. Thanks for all the help.

0

Pavel,
Where do I set the custom login page URL string so that some Teamcity  class will know how to retrieve it? The  jetbrains.buildServer.controllers.login.LoginPageProvider interface has a  single method  getLoginPageUrl(@NotNull HttpServletRequest request). I  assume the URL string will be retrieved from the request object.

0

Sorry, I do not understand the question. Usually login page URL is static and does not need calculation or at least calculation is very simple.

0

Pavel,
         I was under the impression that the jetbrains.buildServer.controllers.login.LoginPageProvider interface allowed me
to define and use a custom login page for example customLogin.jsp instead of the default login.jsp. Maybe I just
don't know how or where to use jetbrains.buildServer.controllers.login.LoginPageProvider I noticed in the Teamcity EAP
distribution that WebLoginModel implemented LoginPageProvider:

public interface WebLoginModel extends LoginPageProvider {

But where will I use WebLoginModel or LoginPageProvider in my plugin implementation? What is the purpose of the LoginPageProvider?
There is no documentation so I am guessing how to use it.

0

Ok, the sample is below:

public class CustomLoginController extends BaseController implements LoginPageProvider {

private PluginDescriptor myPluginDescriptor;

public CustomLoginController(WebControllerManager controllerManager, AuthorizationInterceptor authInterceptor, PluginDescriptor pluginDescriptor) {
controllerManager.registerController("/customLogin.html", this);
authInterceptor.addPathNotRequiringAuth("/customLogin.html"); // required to disable authentication check for this controller url
myPluginDescriptor = pluginDescriptor;
}

public String getLoginPageUrl(HttpServletRequest request) {
return request.getContextPath() + "/customLogin.html";
}

public ModelAndView doHandle(final HttpServletRequest request, final HttpServletResponse response) throws Exception {
return new ModelAndView(myPluginDescriptor.getPluginResourcesPath("/customLogin.jsp"));
}

}

You need to define this class as Spring bean and you also need to create customLogin.jsp page. Also if you need some processing of requests from login page you will need to add this code too.

Hope this helps.

0

Pavel,
         Thanks I get it now :-) I will try to implement this tomorrow. Will keep you posted.

0

Pavel

1. Can you send me a link to the Teamcity 6.0 EAP (15598)  WAR version. As I need to deploy it to a solaris (unix) box.

2. When will Teamcity 6.0  be released?

0

Paul, today we release EAP build with this extension, you can download it from EAP download page: http://confluence.jetbrains.net/display/TW/Download+Latest

We plan to release TeamCity 6.0 in November.

0

Pavel,
         So the siteminder authentication works with Teamcity but since the authentication scheme has change
and the Teamcity's login page is no longer needed since the user credentials now come from the request header
how can I get the Eclipse Pugin and the Windows Tray interfaces  to work?

0

Well, that's a bit tricky because IDE can't interact with Siteminder. As a workaround maybe you could generate some code for each user authenticated via Siteminder, store it somewhere on the disk and make a custom page where each logged in user could see his own code. Then in your login module, if user authenticates with such code, accept this authentication. Not ideal, but I do not see other ways currently.

0

We are going to use Teamcity's authentication infrastructure after all, in fact, we got our new licenses for TC 6.
We just need to migrate from TC 5.1.1 using the internal DB to TC 6 with oracle. If this works then TC gets used
through out GE :-)

0

Please sign in to leave a comment.