Fix jwt-token
This commit is contained in:
@@ -69,11 +69,16 @@ const TenantModal = ({ isOpen, onClose, tenant = null, onSave }) => {
|
||||
primary_color: '#3B82F6',
|
||||
secondary_color: '#1F2937',
|
||||
company_name: ''
|
||||
}
|
||||
},
|
||||
// IP Restriction settings
|
||||
ip_restriction_enabled: false,
|
||||
ip_whitelist: [],
|
||||
ip_restriction_message: 'Access denied. Your IP address is not authorized to access this tenant.'
|
||||
})
|
||||
|
||||
const [showSecrets, setShowSecrets] = useState(false)
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [newIP, setNewIP] = useState('')
|
||||
|
||||
// Load tenant data when editing
|
||||
useEffect(() => {
|
||||
@@ -85,7 +90,11 @@ const TenantModal = ({ isOpen, onClose, tenant = null, onSave }) => {
|
||||
user_mapping: { ...formData.user_mapping, ...tenant.user_mapping },
|
||||
role_mapping: { ...formData.role_mapping, ...tenant.role_mapping },
|
||||
features: { ...formData.features, ...tenant.features },
|
||||
branding: { ...formData.branding, ...tenant.branding }
|
||||
branding: { ...formData.branding, ...tenant.branding },
|
||||
// IP restriction fields with fallbacks
|
||||
ip_restriction_enabled: tenant.ip_restriction_enabled || false,
|
||||
ip_whitelist: tenant.ip_whitelist || [],
|
||||
ip_restriction_message: tenant.ip_restriction_message || 'Access denied. Your IP address is not authorized to access this tenant.'
|
||||
})
|
||||
}
|
||||
}, [tenant])
|
||||
@@ -106,6 +115,43 @@ const TenantModal = ({ isOpen, onClose, tenant = null, onSave }) => {
|
||||
}))
|
||||
}
|
||||
|
||||
// IP Management functions
|
||||
const addIPToWhitelist = () => {
|
||||
if (!newIP.trim()) {
|
||||
toast.error('Please enter an IP address or CIDR block')
|
||||
return
|
||||
}
|
||||
|
||||
// Basic validation for IP format
|
||||
const ipPattern = /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(?:\/(?:[0-9]|[1-2][0-9]|3[0-2]))?$|^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^\d{1,3}\.\d{1,3}\.\d{1,3}\.\*$/
|
||||
|
||||
if (!ipPattern.test(newIP.trim())) {
|
||||
toast.error('Please enter a valid IP address, CIDR block (e.g., 192.168.1.0/24), or wildcard (e.g., 192.168.1.*)')
|
||||
return
|
||||
}
|
||||
|
||||
const ip = newIP.trim()
|
||||
if (formData.ip_whitelist.includes(ip)) {
|
||||
toast.error('This IP is already in the whitelist')
|
||||
return
|
||||
}
|
||||
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
ip_whitelist: [...prev.ip_whitelist, ip]
|
||||
}))
|
||||
setNewIP('')
|
||||
toast.success('IP added to whitelist')
|
||||
}
|
||||
|
||||
const removeIPFromWhitelist = (ipToRemove) => {
|
||||
setFormData(prev => ({
|
||||
...prev,
|
||||
ip_whitelist: prev.ip_whitelist.filter(ip => ip !== ipToRemove)
|
||||
}))
|
||||
toast.success('IP removed from whitelist')
|
||||
}
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault()
|
||||
setLoading(true)
|
||||
@@ -604,6 +650,120 @@ const TenantModal = ({ isOpen, onClose, tenant = null, onSave }) => {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* IP Restriction Configuration */}
|
||||
<div className="space-y-4">
|
||||
<h4 className="text-md font-medium text-gray-900 border-b pb-2">IP Access Control</h4>
|
||||
|
||||
<div className="flex items-center space-x-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="ip_restriction_enabled"
|
||||
checked={formData.ip_restriction_enabled}
|
||||
onChange={(e) => setFormData(prev => ({
|
||||
...prev,
|
||||
ip_restriction_enabled: e.target.checked
|
||||
}))}
|
||||
className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
|
||||
/>
|
||||
<label htmlFor="ip_restriction_enabled" className="text-sm font-medium text-gray-700">
|
||||
Enable IP Restrictions
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{formData.ip_restriction_enabled && (
|
||||
<div className="space-y-4 p-4 bg-gray-50 rounded-lg">
|
||||
<p className="text-sm text-gray-600">
|
||||
Only IPs in the whitelist below will be able to access this tenant. You can add individual IP addresses, CIDR blocks, or wildcards.
|
||||
</p>
|
||||
|
||||
{/* Add IP Input */}
|
||||
<div className="flex space-x-2">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Enter IP address (e.g., 192.168.1.100, 10.0.0.0/24, or 192.168.1.*)"
|
||||
value={newIP}
|
||||
onChange={(e) => setNewIP(e.target.value)}
|
||||
onKeyPress={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault()
|
||||
addIPToWhitelist()
|
||||
}
|
||||
}}
|
||||
className="flex-1 border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={addIPToWhitelist}
|
||||
className="px-4 py-2 bg-green-600 text-white rounded-md hover:bg-green-700"
|
||||
>
|
||||
Add IP
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* IP Whitelist */}
|
||||
{formData.ip_whitelist.length > 0 && (
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Allowed IP Addresses ({formData.ip_whitelist.length})
|
||||
</label>
|
||||
<div className="space-y-2 max-h-32 overflow-y-auto">
|
||||
{formData.ip_whitelist.map((ip, index) => (
|
||||
<div key={index} className="flex items-center justify-between bg-white px-3 py-2 rounded border">
|
||||
<span className="text-sm font-mono">{ip}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => removeIPFromWhitelist(ip)}
|
||||
className="text-red-600 hover:text-red-800 text-sm"
|
||||
>
|
||||
Remove
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Custom restriction message */}
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Access Denied Message
|
||||
</label>
|
||||
<textarea
|
||||
value={formData.ip_restriction_message}
|
||||
onChange={(e) => setFormData(prev => ({
|
||||
...prev,
|
||||
ip_restriction_message: e.target.value
|
||||
}))}
|
||||
rows={3}
|
||||
className="w-full border border-gray-300 rounded-md px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
placeholder="Message shown when access is denied due to IP restrictions"
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-1">
|
||||
This message will be shown to users whose IP is not in the whitelist.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="bg-yellow-50 border border-yellow-200 rounded-md p-3">
|
||||
<div className="flex">
|
||||
<div className="ml-3">
|
||||
<h3 className="text-sm font-medium text-yellow-800">
|
||||
⚠️ Important Security Notes
|
||||
</h3>
|
||||
<div className="mt-1 text-sm text-yellow-700">
|
||||
<ul className="list-disc list-inside space-y-1">
|
||||
<li>Make sure to include your current IP to avoid being locked out</li>
|
||||
<li>IP restrictions apply to all tenant access including login and API calls</li>
|
||||
<li>Use CIDR notation for IP ranges (e.g., 192.168.1.0/24)</li>
|
||||
<li>Use wildcards for partial matching (e.g., 192.168.1.*)</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Form Actions */}
|
||||
<div className="flex justify-end space-x-3 pt-6 border-t">
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user