Angular-cli: proxyConfig with Windows authentication stopped working after update to 8

Created on 30 May 2019  路  22Comments  路  Source: angular/angular-cli

馃悶 Bug report

Command (mark with an x)


- [ ] new
- [ ] build
- [X] serve
- [ ] test
- [ ] e2e
- [ ] generate
- [ ] add
- [ ] update
- [ ] lint
- [ ] xi18n
- [ ] run
- [ ] config
- [ ] help
- [ ] version
- [ ] doc

Is this a regression?


Yes, the previous version in which this bug was not present was: 7.1.4

Description

When using ng serve with a proxy config to forward all api calls to a .net api hosted on local IIS with windows authentication the browser constantly displays the login dialog.

馃敩 Minimal Reproduction

Create project in ng7 and forward all api calls to IIS with windows authentication using config below, works fine. Update to 8 and authentication fails.


module.exports = {
    '/api/*': {
        target: "http://localhost/api/",
        secure: false,
        logLevel: "debug",
        changeOrigin: true,
        agent: new Agent({
            maxSockets: 100,
            keepAlive: true,
            maxFreeSockets: 10,
            freeSocketTimeout: 30000,
            timeout: 60000,
            keepAliveMsecs: 300000,

        }),
        onProxyRes: proxyRes => {
            let key = 'www-authenticate';
            proxyRes.headers[key] = proxyRes.headers[key] && proxyRes.headers[key].split(',');
        }
    }
};

馃敟 Exception or Error





馃實 Your Environment

Failing environment:


Angular CLI: 8.0.0
Node: 12.3.1
OS: win32 x64
Angular: 8.0.0
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.800.0
@angular-devkit/build-angular     0.800.0
@angular-devkit/build-optimizer   0.800.0
@angular-devkit/build-webpack     0.800.0
@angular-devkit/core              8.0.0
@angular-devkit/schematics        8.0.0
@angular/cdk                      7.2.0
@ngtools/webpack                  8.0.0
@schematics/angular               8.0.0
@schematics/update                0.800.0
rxjs                              6.5.2
typescript                        3.4.5
webpack                           4.30.0

Working environment:


Angular CLI: 7.1.4
Node: 12.3.1
OS: win32 x64
Angular: 7.1.4
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.11.4
@angular-devkit/build-angular     0.11.4
@angular-devkit/build-optimizer   0.11.4
@angular-devkit/build-webpack     0.11.4
@angular-devkit/core              7.1.4
@angular-devkit/schematics        7.1.4
@ngtools/webpack                  7.1.4
@schematics/angular               7.1.4
@schematics/update                0.11.4
rxjs                              6.3.3
typescript                        3.1.6
webpack                           4.23.1

Anything else relevant?

Updated weback-dev-server to 3.3.1 and agentkeepalaive to 4.0.2 to match ng 8.0 in 7.1.4, everything still works in 7.1.4

devkibuild-webpack high regression bufix

Most helpful comment

Same issue here. IE works fine while Chrome doesn't work.

All 22 comments

Hello,

I'm experiencing the same problem after updating my 7.2.x app to 8.

Angular CLI: 8.0.3
Node: 12.4.0
OS: win32 x64
Angular: 8.0.1
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router, service-worker

Package                           Version
-----------------------------------------------------------
@angular-devkit/architect         0.800.3
@angular-devkit/build-angular     0.800.3
@angular-devkit/build-optimizer   0.800.3
@angular-devkit/build-webpack     0.800.3
@angular-devkit/core              7.3.9
@angular-devkit/schematics        7.3.9
@angular/cli                      8.0.3
@angular/pwa                      0.13.9
@ngtools/webpack                  8.0.3
@schematics/angular               7.3.9
@schematics/update                0.800.3
rxjs                              6.5.2
typescript                        3.4.5
webpack                           4.30.0

Application is started using

ng serve --proxy-config proxy.conf.js

The proxy configuration file is similar to the one posted by LukeDi
The first call to the proxied API pops up the basic authentication dialog. It looks like the credentials are never passed to the proxied environment.

Looks like the credentials are not transferred to the proxied environment

I did further testing using different browsers. While Google Chrome and Firefox(with negotiate and ntlm configured) are having a similar behavior (endless password prompt), Internet Explorer is working (at least after an initial password prompt)
Some logs below :
Google Chrome

[HPM] Proxy created: /api  ->  http://localhost:33678
[HPM] Subscribed to http-proxy events:  [ 'error', 'proxyRes', 'close' ]
[HPM] GET /api/core/businessAreas/user -> http://localhost:33678
Begin onProxyRes
www-authenticate "Negotiate, NTLM"
www-authenticate ["Negotiate"," NTLM"]
End onProxyRes
[HPM] GET /api/core/businessAreas/user -> http://localhost:33678
Begin onProxyRes
www-authenticate "Negotiate oYIBFzCCAROgAwoBAaEMBgorBgEEAYI3AgIKooH9BIH6TlRMTVNTUAACAAAAEAAQADgAAAAVwoniaJ+5X4riz4R7AAEAAAAAALIAsgBIAAAACgBjRQAAAA9BAEQALQBTAFcASQBTAFMAAgAQAEEARAAtAFMAVwBJAFMAUwABABoAUwBXAEkAUwBTAC0AUwBJAEUARwAtADEANAAEABgAYQBkAC4AcwB3AGkAcwBzAC4AYwBvAG0AAwA0AFMAVwBJAFMAUwAtAFMASQBFAEcALQAxADQALgBhAGQALgBzAHcAaQBzAHMALgBjAG8AbQAFABgAYQBkAC4AcwB3AGkAcwBzAC4AYwBvAG0ABwAIAKn4ewtgJ9UBAAAAAA=="
www-authenticate ["Negotiate oYIBFzCCAROgAwoBAaEMBgorBgEEAYI3AgIKooH9BIH6TlRMTVNTUAACAAAAEAAQADgAAAAVwoniaJ+5X4riz4R7AAEAAAAAALIAsgBIAAAACgBjRQAAAA9BAEQALQBTAFcASQBTAFMAAgAQAEEARAAtAFMAVwBJAFMAUwABABoAUwBXAEkAUwBTAC0AUwBJAEUARwAtADEANAAEABgAYQBkAC4AcwB3AGkAcwBzAC4AYwBvAG0AAwA0AFMAVwBJAFMAUwAtAFMASQBFAEcALQAxADQALgBhAGQALgBzAHcAaQBzAHMALgBjAG8AbQAFABgAYQBkAC4AcwB3AGkAcwBzAC4AYwBvAG0ABwAIAKn4ewtgJ9UBAAAAAA=="]
End onProxyRes
[HPM] GET /api/core/businessAreas/user -> http://localhost:33678
Begin onProxyRes
www-authenticate "Negotiate, NTLM"
www-authenticate ["Negotiate"," NTLM"]
End onProxyRes

## At this point the password prompt appears, the user types its credentials

[HPM] GET /api/core/businessAreas/user -> http://localhost:33678
Begin onProxyRes
www-authenticate "Negotiate TlRMTVNTUAACAAAAEAAQADgAAAAVgoniWyfcF0P3PWkAAAAAAAAAALIAsgBIAAAACgBjRQAAAA9BAEQALQBTAFcASQBTAFMAAgAQAEEARAAtAFMAVwBJAFMAUwABABoAUwBXAEkAUwBTAC0AUwBJAEUARwAtADEANAAEABgAYQBkAC4AcwB3AGkAcwBzAC4AYwBvAG0AAwA0AFMAVwBJAFMAUwAtAFMASQBFAEcALQAxADQALgBhAGQALgBzAHcAaQBzAHMALgBjAG8AbQAFABgAYQBkAC4AcwB3AGkAcwBzAC4AYwBvAG0ABwAIALMV/hpgJ9UBAAAAAA=="
www-authenticate ["Negotiate TlRMTVNTUAACAAAAEAAQADgAAAAVgoniWyfcF0P3PWkAAAAAAAAAALIAsgBIAAAACgBjRQAAAA9BAEQALQBTAFcASQBTAFMAAgAQAEEARAAtAFMAVwBJAFMAUwABABoAUwBXAEkAUwBTAC0AUwBJAEUARwAtADEANAAEABgAYQBkAC4AcwB3AGkAcwBzAC4AYwBvAG0AAwA0AFMAVwBJAFMAUwAtAFMASQBFAEcALQAxADQALgBhAGQALgBzAHcAaQBzAHMALgBjAG8AbQAFABgAYQBkAC4AcwB3AGkAcwBzAC4AYwBvAG0ABwAIALMV/hpgJ9UBAAAAAA=="]
End onProxyRes
[HPM] GET /api/core/businessAreas/user -> http://localhost:33678
Begin onProxyRes
www-authenticate "Negotiate, NTLM"
www-authenticate ["Negotiate"," NTLM"]
End onProxyRes

Internet Explorer

[HPM] Proxy created: /api  ->  http://localhost:33678
[HPM] Subscribed to http-proxy events:  [ 'error', 'proxyRes', 'close' ]
[HPM] GET /api/core/businessAreas/user -> http://localhost:33678
Begin onProxyRes
www-authenticate "Negotiate, NTLM"
www-authenticate ["Negotiate"," NTLM"]
End onProxyRes
[HPM] GET /api/core/businessAreas/user -> http://localhost:33678
Begin onProxyRes
www-authenticate "Negotiate oYIBFzCCAROgAwoBAaEMBgorBgEEAYI3AgIKooH9BIH6TlRMTVNTUAACAAAAEAAQADgAAAAVwoniJ8/i+M3zH0lpAAEAAAAAALIAsgBIAAAACgBjRQAAAA9BAEQALQBTAFcASQBTAFMAAgAQAEEARAAtAFMAVwBJAFMAUwABABoAUwBXAEkAUwBTAC0AUwBJAEUARwAtADEANAAEABgAYQBkAC4AcwB3AGkAcwBzAC4AYwBvAG0AAwA0AFMAVwBJAFMAUwAtAFMASQBFAEcALQAxADQALgBhAGQALgBzAHcAaQBzAHMALgBjAG8AbQAFABgAYQBkAC4AcwB3AGkAcwBzAC4AYwBvAG0ABwAIAN4QYORWJ9UBAAAAAA=="
www-authenticate ["Negotiate oYIBFzCCAROgAwoBAaEMBgorBgEEAYI3AgIKooH9BIH6TlRMTVNTUAACAAAAEAAQADgAAAAVwoniJ8/i+M3zH0lpAAEAAAAAALIAsgBIAAAACgBjRQAAAA9BAEQALQBTAFcASQBTAFMAAgAQAEEARAAtAFMAVwBJAFMAUwABABoAUwBXAEkAUwBTAC0AUwBJAEUARwAtADEANAAEABgAYQBkAC4AcwB3AGkAcwBzAC4AYwBvAG0AAwA0AFMAVwBJAFMAUwAtAFMASQBFAEcALQAxADQALgBhAGQALgBzAHcAaQBzAHMALgBjAG8AbQAFABgAYQBkAC4AcwB3AGkAcwBzAC4AYwBvAG0ABwAIAN4QYORWJ9UBAAAAAA=="]
End onProxyRes
[HPM] GET /api/core/businessAreas/user -> http://localhost:33678
Begin onProxyRes
www-authenticate "Negotiate, NTLM"
www-authenticate ["Negotiate"," NTLM"]
End onProxyRes

## At this point the password prompt appears, the user types its credentials

[HPM] GET /api/core/businessAreas/user -> http://localhost:33678
Begin onProxyRes
www-authenticate "Negotiate oYG2MIGzoAMKAQChCwYJKoZIgvcSAQICooGeBIGbYIGYBgkqhkiG9xIBAgICAG+BiDCBhaADAgEFoQMCAQ+ieTB3oAMCARKicARuyivBH37Wpp+3dmyMTQxiCyVljCHDv/hzWgDixoj6bfiNHtm9n3shtiqNjBSyid3AH13JbxMPR4P2/lOf19i5KdKkb+cwyvAu9nE73WXtNe7OzJfwU2n74Vj7b0xdVGMD41a9pBBG8opGmL2DbKk="
www-authenticate ["Negotiate oYG2MIGzoAMKAQChCwYJKoZIgvcSAQICooGeBIGbYIGYBgkqhkiG9xIBAgICAG+BiDCBhaADAgEFoQMCAQ+ieTB3oAMCARKicARuyivBH37Wpp+3dmyMTQxiCyVljCHDv/hzWgDixoj6bfiNHtm9n3shtiqNjBSyid3AH13JbxMPR4P2/lOf19i5KdKkb+cwyvAu9nE73WXtNe7OzJfwU2n74Vj7b0xdVGMD41a9pBBG8opGmL2DbKk="]
End onProxyRes
[HPM] GET /api/core/businessAreas/user -> http://localhost:33678
Begin onProxyRes
www-authenticate "Negotiate oYG2MIGzoAMKAQChCwYJKoZIgvcSAQICooGeBIGbYIGYBgkqhkiG9xIBAgICAG+BiDCBhaADAgEFoQMCAQ+ieTB3oAMCARKicARuZWc6Q05giVBMb2rV72A3KNWiWB4G91zIkqqM5uaZz3gIe1VL1aWC0DdZu5HuS9ZnMvTnEv5hTeYWWD6ph0JryStHjZjak6mcBOVycnQWMJXh19d8cHYA0F9TcEvBy2a9xC6pmBdPC9amgnxuVzE="
www-authenticate ["Negotiate oYG2MIGzoAMKAQChCwYJKoZIgvcSAQICooGeBIGbYIGYBgkqhkiG9xIBAgICAG+BiDCBhaADAgEFoQMCAQ+ieTB3oAMCARKicARuZWc6Q05giVBMb2rV72A3KNWiWB4G91zIkqqM5uaZz3gIe1VL1aWC0DdZu5HuS9ZnMvTnEv5hTeYWWD6ph0JryStHjZjak6mcBOVycnQWMJXh19d8cHYA0F9TcEvBy2a9xC6pmBdPC9amgnxuVzE="]
End onProxyRes

Interesting, I'm not having much luck with IE. Same issue as Chrome.

I am thinking this might be related to https://github.com/angular/angular-cli/issues/14743 can you please check if adding crossorigin works?

Having the same problem here.

How can I test #14743 locally? I cloned the repo and ran yarn/yarn link but when I run ng new I get:

C:\Temp\devangular-cli-masterangular-cli-master>ng new test
Cannot find module 'C:\Temp\devangular-cli-masterangular-cli-master\node_modul
es\@schematicsangular\ng-new'

Please find attached a sample project to reproduce the issue (sorry couldnt create a repo from it due to weird corporate restrictions). GitHub14595.zip

The zip file contains the following elements

  • A vanilla ASP Mvc web application with windows authentication enabled (you will need Visual Studio to run it, make sure you restore the nuget packages before running it). The app has a single method endpoint ("/Api/User") which retrieves and returns the currently logged in user.
  • A vanilla angular 7 app which configured to proxy all the requests to /api to the Asp application (the npm startup script takes care of including the proxy config file).
  • The same angular app migrated to angular 8.

Running the web app and the Angular 7 app is working fine, the credentials are proxied as expected. Running the web app and the Angular 8 app does not work and traps the user in an infinite credentials prompt loop.

Hope this helps

Same issue here. IE works fine while Chrome doesn't work.

@fredjeck were you able to find a work around for this using Angular 8?

@fredjeck were you able to find a work around for this using Angular 8?

Yes I found something, now instead of workaround I would better qualify it as a "ugly dirty fix"
As the issue is only bugging the team while developping (failure to proxy the credentials to the proxied API) I added a couple of #IF DEBUG statements in the code handling the user forcing the user to the one logged in (System.Security.Principal.WindowsIdentity.GetCurrent().Name) and disabling windows auth and restoring anonymous auth on the API side.

It is dirty but works. Impacts are limited to the development environment as the CI takes care of cleaning up everything for all of the others environments.

Thanks @fredjeck ! We were considering a similar ugly work around, but weren't sure how well it would work. We will probably now take a crack at implementing the same fix.

Same Issue infinite credential prompts over chrome and firefox, works in IE. Got it worked with similar 'ugly work around' as suggested by @fredjeck.

For anyone else coming across this in need of a similar fix here's a snippet of what the work around we implemented looks like. Hope this helps save someone the significant time we lost on this.

public class AuthorizeAttribute : System.Web.Http.AuthorizeAttribute
{
protected override bool IsAuthorized(HttpActionContext actionContext)
{

if DEBUG

        actionContext.RequestContext.Principal = new GenericPrincipal(new GenericIdentity("domain\\username"), new string[] { });

endif

Same issue here, we are using proxyConfig to make window authentication. It is failing in an infinite credential prompts since the upgrade to angular 8. We got the exact same behaviour as fredjeck, 2 calls that look like Negociate works, but the third one act like nothing happened. It behave like when the keepalive proxy wasn't working, but it might be something else...
The workaround for us... has been to rollback everything to angular 7 :D

The workaround for us... has been to rollback everything to angular 7

Hi, same problem here.

So I understand the problem but don't know how to fix it.

The problem is the proxy socket implementation will open a new socket on http status 401, instead of re-using the existing socket.

I'm attaching a wireshark packet capture that sheds light on the issue.

angular-8-ntlm-fail.zip

I also compared package usages between v7 and v8. I downgraded v8 webpack-dev-server to use v7 and problem is still present. I downgraded http-proxy-middleware and the problem is still present.

Now I'm thinking it may have to do with how ng serve configures the dev server on startup.

Here is my proxy.config.js that works in v7 but fails in v8.

const http = require('http');

module.exports = {
    '/api': {
        target: 'http://localhost:62344',
        secure: false,
        logLevel: 'debug',
        agent: new http.Agent({ 
            keepAlive: true,
            keepAliveMsecs: 1000,
            timeout: 9999999
        }),
        onProxyRes: (proxyRes, req, res) => {
            let key = 'www-authenticate';
            proxyRes.headers[key] = proxyRes.headers[key] && proxyRes.headers[key].split(',');

        }
    }
};

So I manually setup a webpack's dev server w/proxy (see attached zip) using the same version numbers used in Angular 8.x and NTLM authentication works.

So... it appears like Angular is configuring or doing something which prevents NTLM authentication from working? Still looking...

webpack-sample.zip

:smiley: I have found a temporary work around until the Angular team comes up with a patch.

From your Angular project directory, edit the file: node_modules\@angular-devkit\build-webpacksrc\webpack-dev-server\index.js

Comment out the following as shown below:

function runWebpackDevServer(config, context, options = {}) {
    const createWebpack = options.webpackFactory || (config => rxjs_1.of(webpack(config)));
    const log = options.logging
        || ((stats, config) => context.logger.info(stats.toString(config.stats)));
    /*config = webpackMerge(config, {
        plugins: [
            new architect_2.ArchitectPlugin(context),
        ],
    });//*/
    const devServerConfig = options.devServerConfig || config.devServer || {};
    if (devServerConfig.stats) {
        config.stats = devServerConfig.stats;
    }

In summary - just before running the webpack dev-server Angular injects a dev-server plugin called ArchitectPlugin. Why this plugin causes new proxy sockets to be opened rather than reused - I haven't a clue.

@alan-agius4 - can you assign this to a dev who knows the ArchitectPlugin?

I can confirm, commenting out this config line in the index.js solves the problem in the moment.

@VAchris Great job, Chris. Thank you for finding the fix. It was stopping me from moving to 8.

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

_This action has been performed automatically by a bot._

Was this page helpful?
0 / 5 - 0 ratings

Related issues

delasteve picture delasteve  路  3Comments

hareeshav picture hareeshav  路  3Comments

JanStureNielsen picture JanStureNielsen  路  3Comments

rajjejosefsson picture rajjejosefsson  路  3Comments

naveedahmed1 picture naveedahmed1  路  3Comments