Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

O365 connectors within Teams will be deprecated #262

Closed
patrick-hermann-sva opened this issue Jul 8, 2024 · 27 comments · Fixed by #275
Closed

O365 connectors within Teams will be deprecated #262

patrick-hermann-sva opened this issue Jul 8, 2024 · 27 comments · Fixed by #275
Assignees
Milestone

Comments

@patrick-hermann-sva
Copy link

After changing my webhook url to a workflow url. the connector is not working anymore. do you have plans to support workflow urls as well?

Action Required:
O365 connectors within Teams will be deprecated and notifications from this service will stop.
Learn more
about the timing and how the Workflows app provides a more flexible and secure experience. If you want to continue receiving these types of messages, you can use a workflow to post messages from a webhook request.
Set up workflow

2024/07/08 14:21:42 failed to send message: failed to validate webhook URL: webhook URL does not match one of expected patterns; got: "https://prod-28.westeurope.logic.azure.com:443/workflows/c593f4203fdd4790a8407906ee4204f3/triggers/manual/paths/invoke?api-version=2016-06-01", patterns: ^https:\/\/(?:.*\.webhook|outlook)\.office(?:365)?\.com
@atc0005
Copy link
Owner

atc0005 commented Jul 8, 2024

@patrick-hermann-sva,

Thanks for reaching out.

After changing my webhook url to a workflow url. the connector is not working anymore.

For the short term, I recommend replacing the workflow url with a webhook url to restore functionality.

do you have plans to support workflow urls as well?

I hope to do so, but have only just learned about this today when reviewing some active O365 connectors. Ironically in our case I didn't see the deprecation message for notifications delivered via webhook connectors, but RSS connectors.

Based on the "Learn more" link, this appears to be the current deprecation schedule:

We will gradually roll out this change in waves:

Wave 1 – effective August 15th, 2024: All new Connector creation will be blocked within all clouds
Wave 2 – effective October 1st, 2024: All connectors within all clouds will stop working

While I hope to have something before October 1, I won't know for sure until I've had a chance to dig deeper. Unfortunately my time is limited lately, so I can't provide an estimate.


refs:

TODO: Move (most of ?) these links to README when preparing upcoming release

@atc0005 atc0005 pinned this issue Jul 8, 2024
@atc0005
Copy link
Owner

atc0005 commented Jul 9, 2024

Some observations below (mostly notes to myself).


Using curl like so:

webhook_url="placeholder_for_workflow_connector_url"
curl \
    -X POST \
    -H "Content-type: application/json" \
    -d @/path/to/test/payloads/file.json \
    "${webhook_url}"

Working payload (/path/to/test/payloads/simple.json):

{
    "type": "message",
    "attachments": [
        {
            "contentType": "application/vnd.microsoft.card.adaptive",
            "contentUrl": null,
            "content": {
                "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
                "type": "AdaptiveCard",
                "version": "1.2",
                "body": [
                    {
                        "type": "TextBlock",
                        "text": "Title test"
                    },
                    {
                        "type": "TextBlock",
                        "text": "Content test"
                    }
                ]
            }
        }
    ]
}

Here is a payload which works fine when sent to a O365 webhook connector (/path/to/test/payloads/table.json):

Details
{
    "type": "message",
    "attachments": [
        {
            "contentType": "application/vnd.microsoft.card.adaptive",
            "contentUrl": null,
            "content": {
                "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
                "type": "AdaptiveCard",
                "version": "1.5",
                "body": [
                    {
                        "type": "Table",
                        "gridStyle": "accent",
                        "firstRowAsHeaders": true,
                        "showGridLines": false,
                        "columns": [
                            {
                                "type": "TableColumnDefinition",
                                "width": 1
                            },
                            {
                                "type": "TableColumnDefinition",
                                "width": 1
                            },
                            {
                                "type": "TableColumnDefinition",
                                "width": 3
                            }
                        ],
                        "rows": [
                            {
                                "type": "TableRow",
                                "cells": [
                                    {
                                        "type": "TableCell",
                                        "items": [
                                            {
                                                "type": "TextBlock",
                                                "text": "Name",
                                                "wrap": true,
                                                "weight": "Bolder"
                                            }
                                        ]
                                    },
                                    {
                                        "type": "TableCell",
                                        "items": [
                                            {
                                                "type": "TextBlock",
                                                "text": "Type",
                                                "wrap": true,
                                                "weight": "Bolder"
                                            }
                                        ]
                                    },
                                    {
                                        "type": "TableCell",
                                        "items": [
                                            {
                                                "type": "TextBlock",
                                                "text": "Description",
                                                "wrap": true,
                                                "weight": "Bolder"
                                            }
                                        ]
                                    }
                                ],
                                "style": "accent"
                            },
                            {
                                "type": "TableRow",
                                "cells": [
                                    {
                                        "type": "TableCell",
                                        "style": "good",
                                        "items": [
                                            {
                                                "type": "TextBlock",
                                                "text": "columns",
                                                "wrap": true
                                            }
                                        ]
                                    },
                                    {
                                        "type": "TableCell",
                                        "style": "warning",
                                        "items": [
                                            {
                                                "type": "TextBlock",
                                                "text": "ColumnDefinition[]",
                                                "wrap": true
                                            }
                                        ]
                                    },
                                    {
                                        "type": "TableCell",
                                        "style": "accent",
                                        "items": [
                                            {
                                                "type": "TextBlock",
                                                "text": "Defines the table's columns (number of columns, and column sizes).",
                                                "wrap": true
                                            }
                                        ]
                                    }
                                ]
                            },
                            {
                                "type": "TableRow",
                                "cells": [
                                    {
                                        "type": "TableCell",
                                        "style": "good",
                                        "items": [
                                            {
                                                "type": "TextBlock",
                                                "text": "rows",
                                                "wrap": true
                                            }
                                        ]
                                    },
                                    {
                                        "type": "TableCell",
                                        "style": "accent",
                                        "items": [
                                            {
                                                "type": "TextBlock",
                                                "text": "TableRow[]",
                                                "wrap": true
                                            }
                                        ]
                                    },
                                    {
                                        "type": "TableCell",
                                        "style": "attention",
                                        "items": [
                                            {
                                                "type": "TextBlock",
                                                "text": "Defines the rows of the Table, each being a collection of cells. Rows are not required, which allows empty Tables to be generated via templating without breaking the rendering of the whole card.",
                                                "wrap": true
                                            }
                                        ]
                                    }
                                ]
                            }
                        ]
                    },
                    {
                        "type": "Table",
                        "gridStyle": "accent",
                        "firstRowAsHeaders": true,
                        "showGridLines": false,
                        "columns": [
                            {
                                "width": 1
                            },
                            {
                                "width": 1
                            },
                            {
                                "width": 3
                            }
                        ],
                        "rows": [
                            {
                                "type": "TableRow",
                                "cells": [
                                    {
                                        "type": "TableCell",
                                        "items": [
                                            {
                                                "type": "TextBlock",
                                                "text": "Name",
                                                "wrap": true,
                                                "weight": "Bolder"
                                            }
                                        ]
                                    },
                                    {
                                        "type": "TableCell",
                                        "items": [
                                            {
                                                "type": "TextBlock",
                                                "text": "Type",
                                                "wrap": true,
                                                "weight": "Bolder"
                                            }
                                        ]
                                    },
                                    {
                                        "type": "TableCell",
                                        "items": [
                                            {
                                                "type": "TextBlock",
                                                "text": "Description",
                                                "wrap": true,
                                                "weight": "Bolder"
                                            }
                                        ]
                                    }
                                ],
                                "style": "accent"
                            },
                            {
                                "type": "TableRow",
                                "cells": [
                                    {
                                        "type": "TableCell",
                                        "style": "good",
                                        "items": [
                                            {
                                                "type": "TextBlock",
                                                "text": "columns",
                                                "wrap": true
                                            }
                                        ]
                                    },
                                    {
                                        "type": "TableCell",
                                        "style": "warning",
                                        "items": [
                                            {
                                                "type": "TextBlock",
                                                "text": "ColumnDefinition[]",
                                                "wrap": true
                                            }
                                        ]
                                    },
                                    {
                                        "type": "TableCell",
                                        "style": "accent",
                                        "items": [
                                            {
                                                "type": "TextBlock",
                                                "text": "Defines the table's columns (number of columns, and column sizes).",
                                                "wrap": true
                                            }
                                        ]
                                    }
                                ]
                            },
                            {
                                "type": "TableRow",
                                "cells": [
                                    {
                                        "type": "TableCell",
                                        "style": "good",
                                        "items": [
                                            {
                                                "type": "TextBlock",
                                                "text": "rows",
                                                "wrap": true
                                            }
                                        ]
                                    },
                                    {
                                        "type": "TableCell",
                                        "style": "accent",
                                        "items": [
                                            {
                                                "type": "TextBlock",
                                                "text": "TableRow[]",
                                                "wrap": true
                                            }
                                        ]
                                    },
                                    {
                                        "type": "TableCell",
                                        "style": "attention",
                                        "items": [
                                            {
                                                "type": "TextBlock",
                                                "text": "Defines the rows of the Table, each being a collection of cells. Rows are not required, which allows empty Tables to be generated via templating without breaking the rendering of the whole card.",
                                                "wrap": true
                                            }
                                        ]
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        }
    ]
}

but fails to work with a newer workflow connector URL.

If we change the payload like so:

-"version": "1.5"
+"version": "1.2"

then it is accepted via either O365 or workflow connector URLs without issue.

This is even with the Adaptive Cards Schema Explorer noting that version 1.5 is when the Table container type was first introduced.

EDIT:

If we change the payload like so:

-"version": "1.5"
+"version": "1.2"

then it is accepted via either O365 or workflow connector URLs without issue.

This seems to apply to even the simple payload. Thus far it does not appear that 1.5 is accepted. If I drop the value to 1.4 the payload is accepted via either connector URL:

{
    "type": "message",
    "attachments": [
        {
            "contentType": "application/vnd.microsoft.card.adaptive",
            "contentUrl": null,
            "content": {
                "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
                "type": "AdaptiveCard",
                "version": "1.4",
                "body": [
                    {
                        "type": "TextBlock",
                        "text": "Title test"
                    },
                    {
                        "type": "TextBlock",
                        "text": "Content test"
                    }
                ]
            }
        }
    ]
}

@atc0005
Copy link
Owner

atc0005 commented Jul 9, 2024

After some tinkering this AM I don't think the necessary changes will be that invasive (shouldn't require a v3 bump).

I've got some more testing to do, but in short:

I've got this working locally, but need to test further to make sure I'm not overlooking anything.

EDIT:

I don't think the necessary changes will be that invasive (shouldn't require a v3 bump).

That said, I've not tested the Legacy MessageCard support at all with a Workflow connector. I suspect that it won't work.


@atc0005 atc0005 self-assigned this Jul 9, 2024
@atc0005 atc0005 added this to the Next Release milestone Jul 9, 2024
@patrick-hermann-sva
Copy link
Author

hi @atc0005, thank you for your detailed messages/research and local testing. sounds great & thank you for your great work - looking forward to the next release 🚀

atc0005 added a commit that referenced this issue Jul 12, 2024
- add directions for creating new Power Automate workflow
  connectors
- heavily emphasize deprecation of legacy MessageCard format
  and O365 connectors
- update Supported Release section to share plans for current
  v2 series and upcoming v3 series

refs GH-262
atc0005 added a commit that referenced this issue Jul 12, 2024
- lower `AdaptiveCardMaxVersion` from `1.5` to `1.4`
  - this almost seems like a bug on Teams' end as this limitation is
    not communicated (from what I could tell) via
    https://adaptivecards.io/designer/
  - using a value of `1.4` appears to work equally well for O365 and
    Workflow connectors
- treat a 202 response code as sufficient response verification
  - instead of expecting a `1` in the response body as previously
    confirmed
  - see also #59
- add `logic.azure.com` to valid URL patterns for default validation
- debugging / troubleshooting
    - log status code and response string for O365 connector responses
    - log validation pattern match

refs GH-262
@atc0005
Copy link
Owner

atc0005 commented Jul 12, 2024

@patrick-hermann-sva

First pre-release:

The bulk of the changes pertain to documentation updates (#263). Minimal code changes have been applied (#265).

If you're able, please test and provide feedback. I'll be performing similar tests today and next week as I switch some jobs over to using Workflow connectors.

@tmu-sprd
Copy link

Sorry for hopping in.

Tested it with https://github.com/voxpupuli/webhook-go (Teams integration: https://github.com/voxpupuli/webhook-go/blob/master/lib/chatops/teams.go) and it works. Thank you.

@atc0005
Copy link
Owner

atc0005 commented Jul 12, 2024

@tmu-sprd Thanks for the testing & feedback.

The more testing/feedback from others the better.

All,

See also:

@patrick-hermann-sva
Copy link
Author

hi @atc0005 thank you! adaptivecards are working for me in v2.11.0-alpha.1 :-), thank you again! messagecard still not, because of the pattern of the url.

patterns: ^https:\/\/(?:.*\.webhook|outlook)\.office(?:365)?\.com

@atc0005
Copy link
Owner

atc0005 commented Jul 16, 2024

@patrick-hermann-sva What error are you receiving?

@patrick-hermann-sva
Copy link
Author

@atc0005 webhooks can not be send (messagecard only), because workflow url differs from the old o365 url (regex)

@atc0005
Copy link
Owner

atc0005 commented Jul 16, 2024

Hi @patrick-hermann-sva,

Just to make sure I understand, when you test the v2.11.0-alpha.1 release you're still receiving the same error you initially reported?

In my testing I'm seeing at least one additional pattern in the list (logic.azure.com) provided by the error message when I specify a webhook URL that doesn't match the expected patterns list.

Snippet of the error message that I see (when using this library from another application):

patterns: ^https:\/\/(?:.*\.webhook|outlook)\.office(?:365)?\.com,logic.azure.com

Can you share the exact error you're seeing (please feel free to substitute UUID tenant value) ?

@SkonWodrich
Copy link

@atc0005 Hello Adam ... ich stll get the validation error, becuase i still habe the same regExpr in 2.11.0-alpha.1

in send.go -> DefaultWebhookURLValidationPattern = ^https:\/\/(?:.*\.webhook|outlook)\.office(?:365)?\.com

without the check is could send the card, but i get:

We're sorry, this card couldn't be displayed XXX used a Workflow template to send this card. [Get template]

@patrick-hermann-sva
Copy link
Author

@atc0005 @SkonWodrich hi, sorry i overlooked your answer. same problem for me for with the regex for messagecards. adaptivecards are working in the alpha branch. ( the url for the webhooks changed, i think maybe adjusting the regex is enought to make it work).

@atc0005
Copy link
Owner

atc0005 commented Jul 22, 2024

@patrick-hermann-sva,

If I understand correctly, this works for you when using the v2.11.0-alpha.1 release:

  1. adaptivecards
  2. Power Automate workflow connector

However, you receive a validation error when using:

  1. adaptivecards or messagecards
  2. O365 connector

It sounds like the default webhook URL validation regex does not cover the webhook URLs generated for your Org.

You've probably been disabling webhook URL validation to work around that:

// Disable webhook URL validation
mstClient.SkipWebhookURLValidationOnSend(true)

Alternatively, you can supply a custom pattern for use with validation:

Since we're migrating away from O365 connectors that is probably not a concern for you any longer, but if you'd like to file a separate issue and provide a sanitized version of your webhook URL we can look at extending the validation to cover that use case.

@atc0005
Copy link
Owner

atc0005 commented Jul 22, 2024

@SkonWodrich,

It sounds like the webhook URL regex pattern doesn't cover the webhook URLs generated for your Org either and that you're disabling webhook URL validation to work around that. Another option is to supply a custom pattern for use with validation.

We can also look at extending the validation to cover URLs generated for your Org. Ideally the default validation would work for everyone; if you're interested in helping to extend that default validation support please file a separate GH issue and we can work on that.

The error message you've shared sounds like you're submitting a card in the legacy MessageCard format to a Workflow connector. While the MessageCard format is supported by O365 connectors, the Adaptive Card format is the only one supported by Workflow connectors.

If you're submitting cards to Teams in the Adaptive Card format it may be that this library is improperly generating an Adaptive Card payload and the validation support applied is not catching the problem.

If you are comfortable with sanitizing the payload to remove anything sensitive to your Org and then sharing it here we can troubleshoot that further.

@SkonWodrich
Copy link

SkonWodrich commented Jul 24, 2024

@atc0005 you are right and i already use the optOut for the RegEx. as @patrick-hermann-sva mentioned, the regeEx is not valid anymore begining from october 2024.

Old URL: https://xxxx.webhook.office.com/webhookb2/uuid@uuid/IncomingWebhook/string/uuid
New URL: https://xxxx-12.region[eg. westeurope].logic.azure.com:443/workflows/string 32[0-9a-z]/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=string

does this help ... with your alpha version i could send out messages again, but only when i ignore the regExpr.

@atc0005
Copy link
Owner

atc0005 commented Jul 24, 2024

@SkonWodrich thank you for the additional info.

The validation in the v2.11.0-alpha.1 release was extended to also allow URLs containing logic.azure.com by default, assuming I didn't overlook something.

Could you share a sanitized copy of the error message that you are seeing?

@SkonWodrich
Copy link

SkonWodrich commented Jul 24, 2024

DefaultWebhookURLValidationPattern = ^https:\/\/(?:.*\.webhook|outlook)\.office(?:365)?\.com

hmmm ... i thought this is the regEx @atc0005

EDIT: works now without SkipWebhookURLValidationOnSend. My problem is solved. i guess ...

@patrick-hermann-sva ?

@atc0005
Copy link
Owner

atc0005 commented Jul 24, 2024

Hi @SkonWodrich,

As of the v2.11.0-alpha.1 release that is one of two patterns applied by default.

Can you share the error message that you're getting when you try to use a new Workflow URL with the v2.11.0-alpha.1 release?

@SkonWodrich
Copy link

sorry .. i edited my post .. it works fine now.

@atc0005
Copy link
Owner

atc0005 commented Jul 24, 2024

Additional positive feedback (from @ArcticXWolf) on #268 (comment):

Oh and I am using the v2.11.0-alpha.1 version and go against the new MS Teams Workflow webhook. It works great so far. #262

@atc0005
Copy link
Owner

atc0005 commented Jul 24, 2024

For anyone following this GH issue who hasn't seen it yet, Microsoft has changed some of the details regarding the retirement timeline of O365 connectors:

Update 07/23/2024: We understand and appreciate the feedback that customers have shared with us regarding the timeline provided for the migration from Office 365 connectors. We have extended the retirement timeline through December 2025 to provide ample time to migrate to another solution such as Power Automate, an app within Microsoft Teams, or Microsoft Graph. Please see below for more information about the extension:

  • All existing connectors within all clouds will continue to work until December 2025, however using connectors beyond December 31, 2024 will require additional action.
    • Connector owners will be required to update the respective URL to post by December 31st, 2024. At least 90 days prior to the December 31, 2024 deadline, we will send further guidance about making this URL update. If the URL is not updated by December 31, 2024 the connector will stop working. This is due to further service hardening updates being implemented for Office 365 connectors in alignment with Microsoft’s Secure Future Initiative
  • Starting August 15th, 2024 all new creations should be created using the Workflows app in Microsoft Teams

Since O365 connectors will likely persist in many environments for another 17 months this project will need to continue supporting them. It's not 100% clear to me that O365 connectors will continue to support the legacy MessageCard format, but I suspect that they will.

atc0005 added a commit that referenced this issue Jul 24, 2024
Update README coverage with updated details regarding the
deprecation timeline and current plans for v2 and v3 release
series.

refs GH-262
atc0005 added a commit that referenced this issue Jul 24, 2024
- add directions for creating new Power Automate workflow
  connectors
- heavily emphasize deprecation of legacy MessageCard format
  and O365 connectors
- update Supported Release section to share plans for current
  v2 series and upcoming v3 series

refs GH-262
atc0005 added a commit that referenced this issue Jul 24, 2024
Update README coverage with updated details regarding the
deprecation timeline and current plans for v2 and v3 release
series.

refs GH-262
atc0005 added a commit that referenced this issue Jul 24, 2024
- lower `AdaptiveCardMaxVersion` from `1.5` to `1.4`
  - this almost seems like a bug on Teams' end as this limitation is
    not communicated (from what I could tell) via
    https://adaptivecards.io/designer/
  - using a value of `1.4` appears to work equally well for O365 and
    Workflow connectors
- treat a 202 response code as sufficient response verification
  - instead of expecting a `1` in the response body as previously
    confirmed
  - see also #59
- add `logic.azure.com` to valid URL patterns for default validation
- debugging / troubleshooting
    - log status code and response string for O365 connector responses
    - log validation pattern match

refs GH-262
atc0005 added a commit that referenced this issue Jul 24, 2024
Switch from static base pattern of `logic.azure.com` to a regex
OR pattern to permit either of `logic.azure.com` or
`*.azure-api.net` as has been observed in the wild.

This also has the side effect of resolving potential CodeQL
alerts raised in PR GH-275.

refs GH-262
atc0005 added a commit that referenced this issue Jul 24, 2024
THIS is the regex pattern intended for GH-277.

Previous commit message:

Switch from static base pattern of `logic.azure.com` to a regex
OR pattern to permit either of `logic.azure.com` or
`*.azure-api.net` as has been observed in the wild.

This also has the side effect of resolving potential
CodeQL alerts raised in PR GH-275.

refs GH-262
@atc0005
Copy link
Owner

atc0005 commented Jul 24, 2024

Changes to the default Workflow regex made to permit either of logic.azure.com or *.azure-api.net as has been observed in the wild:

@bbenouarets
Copy link

The deadline was actually extended. However, the URL of the webhooks must be updated again by December 31, 2024.

If other system administrators are having difficulties locating the affected teams:
I have written a small tool in Golang that uses the Graph API to output the affected teams.

Teams Webhook Finder

This has helped us enormously, as Microsoft does not offer its own solution for reading the affected channels and teams. We have over 350 teams in our company, which we would otherwise have had to search through manually.

I hope I could help someone here with this.

Independently of my day job, I would like to create an alternative to the native “incoming webhooks”. Maybe someone will benefit from it.

@atc0005
Copy link
Owner

atc0005 commented Jul 25, 2024

@bbenouarets Thank you for sharing that project.

I don't have the access level in our org to make use of it, but others following this GH issue may and could offer feedback in your repo.

atc0005 added a commit that referenced this issue Jul 25, 2024
Switch from static base pattern of `logic.azure.com` to a regex
OR pattern to permit either of `logic.azure.com` or
`*.azure-api.net` as has been observed in the wild.

This also has the side effect of resolving potential CodeQL
alerts raised in PR GH-275.

refs GH-262
@atc0005
Copy link
Owner

atc0005 commented Jul 25, 2024

First release candidate:

Please sound off with feedback if you test the release (good results or bad).

Thanks in advance.

@atc0005
Copy link
Owner

atc0005 commented Jul 26, 2024

I've got some more testing to do, but in short:

  • lower AdaptiveCardMaxVersion from 1.5 to 1.4

See also:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants