Badgerati / Pode

Pode is a Cross-Platform PowerShell web framework for creating REST APIs, Web Sites, and TCP/SMTP servers
https://badgerati.github.io/Pode
MIT License
844 stars 91 forks source link

Add header Access-Control-Allow-* #676

Closed IBera closed 2 years ago

IBera commented 3 years ago

Question

Hi guys, when I try to add a the following header:

Add-PodeHeader -Name 'Access-Control-Allow-Origin' -Value '*'

I get the following error at the time of execute my 'ps1':

InvalidOperation: C:\Program Files\PowerShell\Modules\Pode\2.0.1\Public\Headers.ps1:47:9 Line | 47 | $WebEvent.Response.Headers.Add($Name, $Value) | ~~~~~~~~~ | You cannot call a method on a null-valued expression.

I think that swagger need this header in order to avoid CORS issues. We're using one container with swagger to attach, another container with our pode application

Fetch errorFailed to fetch http://apiserver:8085/docs/openapi Fetch errorPossible cross-origin (CORS) issue? The URL origin (http://apiserver:8085) does not match the page (http://apiserver:8096). Check the server returns the correct 'Access-Control-Allow-*' headers

Could anyone help us, please? Thanks and regards

Badgerati commented 3 years ago

Hey @IBera,

Add-PodeHeader only works within the scriptblocks for Add-PodeRoute, Add-PodeMiddleware or Add-PodeAuth - as it requires access to the HTTP Response headers for a Request.

If you need the header for everything, then this should do the trick:

Add-PodeMiddleware -Name 'AccessControl' -ScriptBlock {
    Add-PodeHeader -Name 'Access-Control-Allow-Origin' -Value '*'
    return $true
}
IBera commented 3 years ago

Hi Badgerati, I do make the trick, and the API it returns already the headers from any route.

I can test the API from Swagger without authentication and it returns the values ok, but when we try it with basic authentication (AD authentication) it returns the following error.

“ TypeError: Failed to fetch” on valid response

I've added the following headers:

I think, it's a CORS error, but i'm not sure. Thanks for your help.

IBera commented 3 years ago

Hi, it's already working. I added this to my script:

Add-PodeMiddleware -Name 'AccessControl' -ScriptBlock {
    Add-PodeHeader -Name 'Access-Control-Allow-Origin' -Value '*'
    Add-PodeHeader -Name 'Access-Control-Allow-Methods' -Value 'GET, POST, DELETE, PUT, PATCH, OPTIONS'
    Add-PodeHeader -Name 'Access-Control-Allow-Headers' -Value 'Content-Type, api_key, Authorization'
    Add-PodeHeader -Name 'Access-Control-Allow-Credentials' -Value 'true'
    return $true
}

and this other line, because we need the Options verb

Add-PodeRoute -Method Options -Path '/users' -ScriptBlock {
    return $true
}

Can we add this method to all my Poderoutes?

Thanks

Badgerati commented 3 years ago

Hey,

Yes, you should be able to do the following, and it'll create an Options for every path:

Add-PodeRoute -Method Options -Path * -ScriptBlock {
    return $true
}
IBera commented 3 years ago

Hi, I added the line to my script, but it doesn't work. It returns in my docker: (mcr.microsoft.com/powershell latest)

Add-PodeRoute : A positional parameter cannot be found that accepts argument '​​​​'. At /scripts/PodeServer.ps1:51 char:5

but it works in a windows virtual machine. Thanks and regards

Badgerati commented 3 years ago

Just tried myself in docker and it worked 🤔 what happens if you wrap the in quotes like: `""`?

IBera commented 3 years ago

Hi Badgerati the result is the same. We have installed the following version:

Script 2.0.3 Pode Desk

Badgerati commented 3 years ago

Hey, does this still happen in 2.1.0?

I've a feeling it might, but worth a check. Any chance you could show more of the script/dockerfile? I'm wondering if there's a something wrong with a function call prior that's making it throw the error 🤔

IBera commented 3 years ago

Hi Badgerati, of course:

dockerfile:

FROM mcr.microsoft.com/powershell

RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y ldap-utils && apt-get clean

Set working directory so stuff doesn't end up in /

WORKDIR /root

Install VMware modules from PSGallery

SHELL [ "pwsh", "-command" ] RUN Set-PSRepository -Name PSGallery -InstallationPolicy Trusted RUN Install-Module VMware.PowerCLI RUN Install-Module Pode RUN install-module psframework RUN Install-Module -Name Microsoft.PowerShell.SecretManagement -Repository PSGallery RUN Install-Module -Name Microsoft.PowerShell.SecretStore -Repository PSGallery

Set PowerCLI Configuration

RUN Set-PowerCLIConfiguration -Scope AllUsers -ParticipateInCEIP $false -Confirm:$false  RUN Set-PowerCLIConfiguration -Scope AllUsers -InvalidCertificateAction Ignore -Confirm:$false  RUN Set-PowerCLIConfiguration -Scope AllUsers -DefaultVIServerMode Single -Confirm:$false  RUN Set-PowerCLIConfiguration -Scope AllUsers -ProxyPolicy NoProxy -Confirm:$false

CMD ["/usr/bin/pwsh"]

Pode Script:

Import-Module /scripts/DeployVM/Main/New-ADCVM.psm1 -Force Import-Module /scripts/DeployVM/Modules/New-ResultObject.psm1 -force

create a server, and start listening on port 8085

Start-PodeServer -Threads 2 {

### listen on localhost:8085
Add-PodeEndpoint -Address * -Port 8085 -Protocol Http
New-PodeLoggingMethod -Terminal | Enable-PodeErrorLogging

### setup session details
Enable-PodeSessionMiddleware -Secret 'schwifty' -Duration (30*60) -Extend -UseHeaders -Strict

Add-PodeMiddleware -Name 'AccessControl' -ScriptBlock {
    Add-PodeHeader -Name 'Access-Control-Allow-Origin' -Value '*'
    Add-PodeHeader -Name 'Access-Control-Allow-Methods' -Value 'GET, POST, DELETE, PUT, PATCH, OPTIONS'
    Add-PodeHeader -Name 'Access-Control-Allow-Headers' -Value 'Content-Type, api_key, Authorization'
    Add-PodeHeader -Name 'Access-Control-Allow-Credentials' -Value 'true'
    return $true
}

### setup form auth against windows AD (<form> in HTML)
New-PodeAuthScheme -Basic | Add-PodeAuthWindowsAd -Name 'Login' -Groups @('Group1', 'Group2') -fqdn ourfqdn.es

This part generate the error

<#Add-PodeRoute -Method Options -Path * -ScriptBlock {​​​​
    return $true
}​​#>

### login check:

Add-PodeRoute -Method Post -Path '/login' -Authentication Login -Login -ScriptBlock {
}

# logout check:

Add-PodeRoute -Method Post -Path '/logout' -Authentication Login -Logout

### Options method. Needed for authentication

Add-PodeRoute -Method Options -Path '/examples/users' -ScriptBlock {
    return $true
}

### Get Method User example 
Add-PodeRoute -Method Get -Path '/examples/users' -Authentication Login -ScriptBlock {
    Write-PodeJsonResponse -Value @{
        Users = @(
            @{
                Name = 'Deep Thought'
                Age = 42
            },
            @{
                Name = 'Leeroy Jenkins'
                Age = 1337
            }
        )
    }
}

Add-PodeRoute -Method Get -Path '/examples/info' -ScriptBlock {
    Write-PodeJsonResponse -Value @{ Name = 'Rick' }
}

### Route to create Virtual Machines
Add-PodeRoute -Method Post -Path '/api/vmware/vm' -Authentication Login -ContentType 'application/json' -ScriptBlock {

    try {
        $result = New-EHCADCVM -ParamJson $WebEvent.Data -Creator $WebEvent.Auth.User.Username
        Write-PodeJsonResponse -Value $result
        }
    Catch {
        $result | Out-PodeHost
        Write-PodeJsonResponse -Value @{'ScriptError' = $_.FullyQualifiedErrorId;}
        }
    }
}

Thanks and regards

Badgerati commented 3 years ago

I've had a look, but I can't see anything obvious that would cause the error to throw 🤔

What happens if you change that route to one of these:

Add-PodeRoute -Method Options -Path * -ScriptBlock {​​​​}

# or, change the path

Add-PodeRoute -Method Options -Path '/testing' -ScriptBlock {​​​​}

When the error is thrown, if you're able to, could you get the output of $error[0] and $error[0].ScriptStackTrace? Hopefully they might contain a little more info

krokofant commented 3 years ago

While fixing this in my own app I noticed that the documentation for Add-PodeMiddleware it's not clear that it needs to return true to be able to work.

Badgerati commented 3 years ago

Aah, that's a good idea; it is mentioned here, but adding it into the function's summary docs makes sense!

Badgerati commented 2 years ago

I'm closing this issue, but if it's still causing problems please feel free to re-open 😃