Search code examples
active-directorysingle-sign-onoffice365adfsws-federation

How do you bypass the Microsoft Online "Stay signed in" when doing WS-Federated login?


I am doing logins to Microsoft Sharepoint Online through an AD-Sycned ADFS using SAML1.1 and WS-federation.

I obtain a saml assertion first from ADFS. Then I submit a web request:

HTTP POST: https://login.microsoftonline.com/login.srf

Content-Type: application/x-www-form-urlencoded

With Form:

wa = wsignin1.0

wctx = my web ctx

wresult = my saml assertion

Response: I clearly was able to log in, but instead of getting a page where I can obtain the token from, I get this page: enter image description here

I found this page but my admins won't let me make the change it suggests which is company wide: https://cloudblogs.microsoft.com/enterprisemobility/2017/09/19/fewer-login-prompts-the-new-keep-me-signed-in-experience-for-azure-ad-is-in-preview/

How can I bypass this response during ADFS ws federated login?


Solution

  • Had to do what everyone else does in this situation when using Microsoft's terribly undocumented api's is to use fiddler to find out what to do.

    Basically I turned on Fiddler, enabled HTTPS decryption support, then ran a login from an incognito browser window.

    This shows me what form Post to emulate.

    The following java code is what I came up with as a result, and it works:

        Map configMap = getRememberMePageConfigMap(wsfedRes);
        if (configMap != null) {
          String sFT = (String) configMap.get("sFT");
          String sFTName = (String) configMap.get("sFTName");
          String ctx = (String) configMap.get("sCtx");
          if (StringUtils.isNotBlank(sFT) && StringUtils.isNotBlank(sFTName) && StringUtils.isNotBlank(ctx)) {
            LOG.info("Found the \"Remember Me\" page when we requested ws-federated auth token. Bypassing it.");
            HttpPost rememberMePost = new HttpPost(MICROSOFT_ONLINE_LOGIN_KMSI_URL);
            List<NameValuePair> wsFedFormParams = new ArrayList<>(3);
            wsFedFormParams.add(new BasicNameValuePair(sFTName, sFT));
            wsFedFormParams.add(new BasicNameValuePair("ctx", ctx));
            wsFedFormParams.add(new BasicNameValuePair("LoginOptions", "0"));
            rememberMePost.setHeader("Content-Type", "application/x-www-form-urlencoded");
            rememberMePost.setHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8");
            rememberMePost.setEntity(new UrlEncodedFormEntity(wsFedFormParams));
            try (CloseableHttpResponse response = client.execute(rememberMePost)) {
              String content = IOUtils.toString(response.getEntity().getContent(), "UTF-8");
              if (diagnosticMode) {
                LOG.info("After posting to {} to bypass the \"Remember me\" page, got statusCode={}, response={}",
                    MICROSOFT_ONLINE_LOGIN_KMSI_URL, response.getStatusLine().getStatusCode(), content);
              }
              return content;
            }
          }
        }
    

    Where getRememberMePageConfigMap is

    Map getRememberMePageConfigMap(String wsfedRes) throws IOException {
        String lines[] = wsfedRes.split("\\r?\\n");
        for (String line : lines) {
          if (line.startsWith("$Config=")) {
            String jsonToParse = line.substring("$Config=".length());
            return OBJECT_MAPPER.readValue(jsonToParse, Map.class);
          }
        }
        return null;
      }
    

    This extra request correctly bypasses the form.