wso2 / product-is

Welcome to the WSO2 Identity Server source code! For info on working with the WSO2 Identity Server repository and contributing code, click the link below.
http://wso2.github.io/
Apache License 2.0
734 stars 715 forks source link

Integrate Branding capabilities to the Authentication, Recovery & My Account portals using `file_based` approach. #15729

Closed brionmario closed 1 year ago

brionmario commented 1 year ago

Is your feature request related to a problem? Please describe.

ATM, there's no way to add branding to the Authentication, Recovery and My Account portal OOTB. The current approach to brand Authentication and Recovery is to go through a manual process that doesn't have any framework (https://is.docs.wso2.com/en/latest/references/extend/rebranding/rebrand-identity-server-uis/).

Describe the solution you would prefer It would be better to implement a structured OOTB branding support that's unified across the portals. This approach can be file-based, maybe based on a JSON file. And users could persist the branding per organization and app wise as well.

brionmario commented 1 year ago

Progress as per (09-06-2023)

Authentication / Recovery

Extensions folder structure.

extensions
└── branding
    ├── APP # app wise branding
    │   └── peoplehr
    │       └── en-US
    │           ├── branding-preference.json
    │           └── stylesheets
    │               └── override.css
    └── ORG # tenant wise branding
        ├── rusticfox.com
        │   └── en-US
        │       ├── branding-preference.json
        │       └── stylesheets
        │           └── override.css
        └── netflix.com
            └── en-US
                ├── branding-preference.json
                └── stylesheets
                    └── override.css

Sample rusticfox.com tenant's customization.

Screenshot 2023-06-08 at 14 01 28

My Account

Extensions folder structure.

extensions
└── branding
    ├── rusticfox.com
    │   └── en-US
    │       ├── branding-preference.json
    │       └── stylesheets
    │           └── override.css
    └── netflix.com
        └── en-US
            ├── branding-preference.json
            └── stylesheets
                └── override.css

Sample rusticfox.com tenant's customization.

Screenshot 2023-06-08 at 14 08 37

Structure of the branding-preference.json.

{
  "type": "ORG",
  "name": "netflixdemo",
  "locale": "en-US",
  "preference": {
    "configs": {
      "isBrandingEnabled": true,
      "removeDefaultBranding": false
    },
    "layout": {
      "activeLayout": "centered"
    },
    "organizationDetails": {
      "copyrightText": "© Netflix Inc 2023. All Rights Reserved.",
      "siteTitle": "Netflix",
      "supportEmail": "support@netflixdemo.com"
    },
    "theme": {
      "activeTheme": "DARK",
      "LIGHT": {
        "buttons": {
          "externalConnection": {
            "base": {
              "background": {
                "backgroundColor": "#FFFFFF"
              },
              "border": {
                "borderRadius": "4px"
              },
              "font": {
                "color": "#000000de"
              }
            }
          },
          "primary": {
            "base": {
              "border": {
                "borderRadius": "4px"
              },
              "font": {
                "color": "#ffffffe6"
              }
            }
          },
          "secondary": {
            "base": {
              "border": {
                "borderRadius": "4px"
              },
              "font": {
                "color": "#000000de"
              }
            }
          }
        },
        "colors": {
          "alerts": {
            "error": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#ffd8d8",
              "inverted": ""
            },
            "info": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#eff7fd",
              "inverted": ""
            },
            "neutral": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#f8f8f9",
              "inverted": ""
            },
            "warning": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#fff6e7",
              "inverted": ""
            }
          },
          "background": {
            "body": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#fbfbfb",
              "inverted": ""
            },
            "surface": {
              "contrastText": "",
              "dark": "#0000000d",
              "light": "#f9fafb",
              "main": "#ffffff",
              "inverted": "#212A32"
            }
          },
          "illustrations": {
            "accent1": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#3865B5",
              "inverted": ""
            },
            "accent2": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#19BECE",
              "inverted": ""
            },
            "accent3": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#FFFFFF",
              "inverted": ""
            },
            "primary": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#FF7300",
              "inverted": ""
            },
            "secondary": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#E0E1E2",
              "inverted": ""
            }
          },
          "outlined": {
            "default": "#dadce0"
          },
          "primary": {
            "contrastText": "",
            "dark": "",
            "light": "",
            "main": "#FF7300",
            "inverted": ""
          },
          "secondary": {
            "contrastText": "",
            "dark": "",
            "light": "",
            "main": "#E0E1E2",
            "inverted": ""
          },
          "text": {
            "primary": "#000000de",
            "secondary": "#00000066"
          }
        },
        "footer": {
          "border": {
            "borderColor": ""
          },
          "font": {
            "color": ""
          }
        },
        "images": {
          "favicon": {},
          "logo": {},
          "myAccountLogo": {
            "title": "Account"
          }
        },
        "inputs": {
          "base": {
            "background": {
              "backgroundColor": "#FFFFFF"
            },
            "border": {
              "borderColor": "",
              "borderRadius": "8px"
            },
            "font": {
              "color": ""
            },
            "labels": {
              "font": {
                "color": ""
              }
            }
          }
        },
        "loginBox": {
          "background": {
            "backgroundColor": ""
          },
          "border": {
            "borderColor": "",
            "borderRadius": "12px",
            "borderWidth": "1px"
          },
          "font": {
            "color": ""
          }
        },
        "page": {
          "background": {},
          "font": {}
        },
        "typography": {
          "font": {
            "fontFamily": "Gilmer"
          },
          "heading": {
            "font": {
              "color": ""
            }
          }
        },
        "loginPage": {
          "background": {
            "backgroundColor": ""
          },
          "font": {
            "color": ""
          }
        }
      },
      "DARK": {
        "buttons": {
          "externalConnection": {
            "base": {
              "background": {
                "backgroundColor": "#24292e"
              },
              "border": {
                "borderRadius": "4px"
              },
              "font": {
                "color": "#ffffff"
              }
            }
          },
          "primary": {
            "base": {
              "border": {
                "borderRadius": "4px"
              },
              "font": {
                "color": "#ffffff"
              }
            }
          },
          "secondary": {
            "base": {
              "border": {
                "borderRadius": "4px"
              },
              "font": {
                "color": "#000000"
              }
            }
          }
        },
        "colors": {
          "alerts": {
            "error": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#ff000054",
              "inverted": ""
            },
            "info": {
              "contrastText": "",
              "dark": "#01579b",
              "light": "#03a9f4",
              "main": "#1971c233",
              "inverted": ""
            },
            "neutral": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#343a4033",
              "inverted": ""
            },
            "warning": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#f08c0033",
              "inverted": ""
            }
          },
          "background": {
            "body": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#141414",
              "inverted": ""
            },
            "surface": {
              "contrastText": "",
              "dark": "#1e2021",
              "light": "#1c1c1c",
              "main": "#000000bf",
              "inverted": "#17191a"
            }
          },
          "illustrations": {
            "accent1": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#3865B5",
              "inverted": ""
            },
            "accent2": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#19BECE",
              "inverted": ""
            },
            "accent3": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#FFFFFF",
              "inverted": ""
            },
            "primary": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#e50914",
              "inverted": ""
            },
            "secondary": {
              "contrastText": "",
              "dark": "",
              "light": "",
              "main": "#E0E1E2",
              "inverted": ""
            }
          },
          "outlined": {
            "default": "#00000003"
          },
          "primary": {
            "contrastText": "",
            "dark": "",
            "light": "",
            "main": "#e50914",
            "inverted": ""
          },
          "secondary": {
            "contrastText": "",
            "dark": "",
            "light": "",
            "main": "#E0E1E2",
            "inverted": ""
          },
          "text": {
            "primary": "#ffffff",
            "secondary": "#b3b3b3"
          }
        },
        "footer": {
          "border": {
            "borderColor": ""
          },
          "font": {
            "color": ""
          }
        },
        "images": {
          "favicon": {
            "imgURL": "https://cdn.statically.io/gh/brionmario/asgardeo-branding/restructure/organizations/netflix/images/favicon.ico"
          },
          "logo": {
            "imgURL": "https://cdn.statically.io/gh/brionmario/asgardeo-branding/restructure/organizations/netflix/images/logo.png",
            "altText": "Logo "
          },
          "myAccountLogo": {
            "title": "Account",
            "imgURL": "https://cdn.statically.io/gh/brionmario/asgardeo-branding/restructure/organizations/netflix/images/logo.png",
            "altText": ""
          }
        },
        "inputs": {
          "base": {
            "background": {
              "backgroundColor": "#333333"
            },
            "border": {
              "borderColor": "",
              "borderRadius": "4px"
            },
            "font": {
              "color": ""
            },
            "labels": {
              "font": {
                "color": ""
              }
            }
          }
        },
        "loginBox": {
          "background": {
            "backgroundColor": ""
          },
          "border": {
            "borderColor": "",
            "borderRadius": "4px",
            "borderWidth": "1px"
          },
          "font": {
            "color": ""
          }
        },
        "page": {
          "background": {},
          "font": {}
        },
        "typography": {
          "font": {
            "fontFamily": "Netflix Sans,Helvetica Neue,Segoe UI,Roboto,Ubuntu,sans-serif",
            "importURL": "https://assets.nflxext.com/ffe/siteui/fonts/netflix-sans/v3/NetflixSans_W_Rg.woff2"
          },
          "heading": {
            "font": {
              "color": ""
            }
          }
        },
        "loginPage": {
          "background": {
            "backgroundColor": ""
          },
          "font": {
            "color": ""
          }
        }
      }
    },
    "stylesheets": {
      "accountApp": "extensions/branding/ORG/netflix.com/en-US/stylesheets/override.css",
      "selfcareApp": "/myaccount/extensions/branding/netflix.com/en-US/stylesheets/override.css"
    },
    "urls": {
      "cookiePolicyURL": "",
      "privacyPolicyURL": ""
    }
  }
}
brionmario commented 1 year ago

Suggested Improvements

Assignee: @Yoshani

1. Folder Structure Improvements

Suggested Structure

Authentication/ Recovery
extensions
└── branding
    ├── rusticfox.com
    │   ├── apps
    │   │   ├── logomaker
    │   │   │   ├── stylesheets
    │   │   │   │   └── override.css
    │   │   │   ├── branding-preference_en_US.json
    │   │   │   └── branding-preference_de_DE.json
    │   │   └── salesforce
    │   │       ├── stylesheets
    │   │       │   └── override.css
    │   │       ├── branding-preference_en_US.json
    │   │       └── branding-preference_de_DE.json
    │   ├── stylesheets
    │   │   └── override.css
    │   ├── branding-preference_en_US.json
    │   └── branding-preference_de_DE.json
    └── wso2.com
        ├── apps
        │   ├── peoplehr
        │   │   ├── stylesheets
        │   │   │   └── override.css
        │   │   ├── branding-preference_en_US.json
        │   │   └── branding-preference_de_DE.json
        │   └── opd-claims
        │       ├── stylesheets
        │       │   └── override.css
        │       ├── branding-preference_en_US.json
        │       └── branding-preference_de_DE.json
        ├── stylesheets
        │   └── override.css
        ├── branding-preference_en_US.json
        └── branding-preference_de_DE.json
My Account
extensions
└── branding
    ├── rusticfox.com
    │   ├── stylesheets
    │   │   └── override.css
    │   ├── branding-preference_en_US.json
    │   └── branding-preference_de_DE.json
    └── wso2.com
        ├── stylesheets
        │   └── override.css
        ├── branding-preference_en_US.json
        └── branding-preference_de_DE.json

2. Layout resolver improvements.

Currently, adding layouts should be done manually. (https://is.docs.wso2.com/en/latest/references/extend/rebranding/customizable-login-portal/)

We can make use of the activeLayout property in branding-preference.json to resolve prefered layout.

Logic: https://github.com/wso2/identity-apps/blob/master/java/apps/authentication-portal/src/main/webapp/includes/layout-resolver.jsp

Yoshani commented 1 year ago

Layout resolver improvements

Suggested structure

extensions
└── branding
    ├── rusticfox.com
    │   ├── apps
    │   │   ├── logomaker
    │   │   │   ├── stylesheets
    │   │   │   │   └── override.css
    │   │   │   ├── branding-preference_en_US.json
    │   │   │   ├── branding-preference_de_DE.json
    │   │   │   └── layouts
    │   │   │       ├── centered
    │   │   │       │   ├── body.ser
    │   │   │       │   └── body.html
    │   │   │       └── top-left
    │   │   │           ├── body.ser
    │   │   │           └── body.html
    │   │   └── salesforce
    │   │       ├── stylesheets
    │   │       │   └── override.css
    │   │       ├── branding-preference_en_US.json
    │   │       └── branding-preference_de_DE.json
    │   ├── stylesheets
    │   │   └── override.css
    │   ├── branding-preference_en_US.json
    │   ├── branding-preference_de_DE.json
    │   └── layouts
    │       └── bottom-right
    │           ├── body.ser
    │           └── body.html
    └── wso2.com
        ├── apps
        │   ├── peoplehr
        │   │   ├── stylesheets
        │   │   │   └── override.css
        │   │   ├── branding-preference_en_US.json
        │   │   ├── branding-preference_de_DE.json
        │   │   └── layouts
        │   │       └── custom
        │   │           ├── body.ser
        │   │           └── body.html
        │   └── opd-claims
        │       ├── stylesheets
        │       │   └── override.css
        │       ├── branding-preference_en_US.json
        │       └── branding-preference_de_DE.json
        ├── stylesheets
        │   └── override.css
        ├── branding-preference_en_US.json
        └── branding-preference_de_DE.json

The activeLayout property in branding-preference.json can be used to resolve the preferred layout.

The improvement also facilitates adding fully customised Product Header and Product Footer tenant-wise and app-wise by adding the customised product-title.jsp and product-footer.jsp files into the relevant layouts folder.

Yoshani commented 1 year ago

Final PRs

Docs PR

asekawa commented 9 months ago
Yoshani commented 9 months ago

Fix impacts on-prem environment only.